refactor: suppression duplication templates PDF RGPD + test 100% DevisPdfController

Templates PDF :
- _base.html.twig : blocs verify_box et hmac_section avec contenu par défaut
  (QR code, verify_url, HMAC-SHA256) au lieu de blocs vides
- rgpd_access.html.twig : suppression blocs verify_box et hmac_section dupliqués
  (héritent du parent)
- rgpd_deletion.html.twig : idem
- rgpd_no_data.html.twig : idem

DevisPdfControllerTest (8 tests) :
- testDevisNotFound : devis null lance NotFoundHttpException
- testUnsignedPdfNotSet : unsignedPdf null lance NotFoundHttpException
- testFileNotExists : fichier absent lance NotFoundHttpException
- testUnsignedPdfSuccess : PDF unsigned retourné en BinaryFileResponse
- testSignedPdfSuccess : PDF signed retourné
- testAuditPdfSuccess : PDF audit retourné
- testAccessAsNonEmploye : accès sans ROLE_EMPLOYE (branche checkAccess)
- testDefaultTypeNull : type inconnu lance NotFoundHttpException

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Serreau Jovann
2026-04-03 11:05:44 +02:00
parent f611050741
commit f0a5fdc849
5 changed files with 213 additions and 53 deletions

View File

@@ -44,9 +44,23 @@
<div class="container">
{% block content %}{% endblock %}
{% block verify_box %}{% endblock %}
{% block verify_box %}
<div class="verify-box">
<div class="verify-row">
<div class="verify-qr"><img src="{{ qrcode }}" alt="QR Code"></div>
<div class="verify-info">
<span class="verify-label">Verifier ce document</span>
<p style="margin: 2px 0 4px; font-size: 9px; font-weight: 700;">Scannez le QR code ou consultez le lien ci-dessous.</p>
<span class="verify-label">URL</span>
<span class="verify-url">{{ verify_url }}</span>
</div>
</div>
</div>
{% endblock %}
{% block hmac_section %}{% endblock %}
{% block hmac_section %}
<div class="hmac">HMAC-SHA256 : {{ attestation.hmac }}</div>
{% endblock %}
{% block footer_contact %}
<div style="margin-top: 16px;">

View File

@@ -41,20 +41,3 @@
{% endfor %}
{% endblock %}
{% block verify_box %}
<div class="verify-box">
<div class="verify-row">
<div class="verify-qr"><img src="{{ qrcode }}" alt="QR Code"></div>
<div class="verify-info">
<span class="verify-label">Verifier ce document</span>
<p style="margin: 2px 0 4px; font-size: 9px; font-weight: 700;">Scannez le QR code ou consultez le lien ci-dessous.</p>
<span class="verify-label">URL</span>
<span class="verify-url">{{ verify_url }}</span>
</div>
</div>
</div>
{% endblock %}
{% block hmac_section %}
<div class="hmac">HMAC-SHA256 : {{ attestation.hmac }}</div>
{% endblock %}

View File

@@ -39,20 +39,3 @@
<div class="warning">Cette suppression est irreversible. Aucune donnee relative a cette adresse IP ne subsiste dans nos bases de donnees.</div>
{% endblock %}
{% block verify_box %}
<div class="verify-box">
<div class="verify-row">
<div class="verify-qr"><img src="{{ qrcode }}" alt="QR Code"></div>
<div class="verify-info">
<span class="verify-label">Verifier ce document</span>
<p style="margin: 2px 0 4px; font-size: 9px; font-weight: 700;">Scannez le QR code ou consultez le lien ci-dessous.</p>
<span class="verify-label">URL</span>
<span class="verify-url">{{ verify_url }}</span>
</div>
</div>
</div>
{% endblock %}
{% block hmac_section %}
<div class="hmac">HMAC-SHA256 : {{ attestation.hmac }}</div>
{% endblock %}

View File

@@ -38,20 +38,3 @@
</div>
{% endblock %}
{% block verify_box %}
<div class="verify-box">
<div class="verify-row">
<div class="verify-qr"><img src="{{ qrcode }}" alt="QR Code"></div>
<div class="verify-info">
<span class="verify-label">Verifier ce document</span>
<p style="margin: 2px 0 4px; font-size: 9px; font-weight: 700;">Scannez le QR code ou consultez le lien ci-dessous.</p>
<span class="verify-label">URL</span>
<span class="verify-url">{{ verify_url }}</span>
</div>
</div>
</div>
{% endblock %}
{% block hmac_section %}
<div class="hmac">HMAC-SHA256 : {{ attestation.hmac }}</div>
{% endblock %}

View File

@@ -0,0 +1,197 @@
<?php
namespace App\Tests\Controller;
use App\Controller\DevisPdfController;
use App\Entity\Devis;
use App\Entity\OrderNumber;
use App\Repository\DevisRepository;
use PHPUnit\Framework\TestCase;
use Psr\Container\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class DevisPdfControllerTest extends TestCase
{
private function createContainer(bool $isEmploye = true): ContainerInterface
{
$session = new Session(new MockArraySessionStorage());
$stack = $this->createStub(RequestStack::class);
$stack->method('getSession')->willReturn($session);
$authChecker = $this->createStub(AuthorizationCheckerInterface::class);
$authChecker->method('isGranted')->willReturn($isEmploye);
$container = $this->createStub(ContainerInterface::class);
$container->method('has')->willReturn(true);
$container->method('get')->willReturnMap([
['router', $this->createStub(RouterInterface::class)],
['security.authorization_checker', $authChecker],
['security.token_storage', $this->createStub(TokenStorageInterface::class)],
['request_stack', $stack],
['parameter_bag', $this->createStub(\Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface::class)],
]);
return $container;
}
public function testDevisNotFound(): void
{
$repo = $this->createStub(DevisRepository::class);
$repo->method('find')->willReturn(null);
$controller = new DevisPdfController();
$controller->setContainer($this->createContainer());
$this->expectException(NotFoundHttpException::class);
$controller(1, 'unsigned', $repo, '/tmp');
}
public function testUnsignedPdfNotSet(): void
{
$devis = new Devis(new OrderNumber('04/2026-00001'), 'secret');
$repo = $this->createStub(DevisRepository::class);
$repo->method('find')->willReturn($devis);
$controller = new DevisPdfController();
$controller->setContainer($this->createContainer());
$this->expectException(NotFoundHttpException::class);
$controller(1, 'unsigned', $repo, '/tmp');
}
public function testFileNotExists(): void
{
$devis = new Devis(new OrderNumber('04/2026-00002'), 'secret');
$devis->setUnsignedPdf('nonexistent.pdf');
$repo = $this->createStub(DevisRepository::class);
$repo->method('find')->willReturn($devis);
$controller = new DevisPdfController();
$controller->setContainer($this->createContainer());
$this->expectException(NotFoundHttpException::class);
$controller(1, 'unsigned', $repo, '/tmp');
}
public function testUnsignedPdfSuccess(): void
{
$tmpDir = sys_get_temp_dir().'/devis_test_'.uniqid();
mkdir($tmpDir.'/var/uploads/devis', 0775, true);
file_put_contents($tmpDir.'/var/uploads/devis/test.pdf', '%PDF-test');
$devis = new Devis(new OrderNumber('042026-00003'), 'secret');
$devis->setUnsignedPdf('test.pdf');
$repo = $this->createStub(DevisRepository::class);
$repo->method('find')->willReturn($devis);
$controller = new DevisPdfController();
$controller->setContainer($this->createContainer());
$response = $controller(1, 'unsigned', $repo, $tmpDir);
$this->assertSame(200, $response->getStatusCode());
@unlink($tmpDir.'/var/uploads/devis/test.pdf');
@rmdir($tmpDir.'/var/uploads/devis');
@rmdir($tmpDir.'/var/uploads');
@rmdir($tmpDir.'/var');
@rmdir($tmpDir);
}
public function testSignedPdfSuccess(): void
{
$tmpDir = sys_get_temp_dir().'/devis_test_'.uniqid();
mkdir($tmpDir.'/var/uploads/devis', 0775, true);
file_put_contents($tmpDir.'/var/uploads/devis/signed.pdf', '%PDF');
$devis = new Devis(new OrderNumber('042026-00004'), 'secret');
$devis->setSignedPdf('signed.pdf');
$repo = $this->createStub(DevisRepository::class);
$repo->method('find')->willReturn($devis);
$controller = new DevisPdfController();
$controller->setContainer($this->createContainer());
$response = $controller(1, 'signed', $repo, $tmpDir);
$this->assertSame(200, $response->getStatusCode());
@unlink($tmpDir.'/var/uploads/devis/signed.pdf');
@rmdir($tmpDir.'/var/uploads/devis');
@rmdir($tmpDir.'/var/uploads');
@rmdir($tmpDir.'/var');
@rmdir($tmpDir);
}
public function testAuditPdfSuccess(): void
{
$tmpDir = sys_get_temp_dir().'/devis_test_'.uniqid();
mkdir($tmpDir.'/var/uploads/devis', 0775, true);
file_put_contents($tmpDir.'/var/uploads/devis/audit.pdf', '%PDF');
$devis = new Devis(new OrderNumber('042026-00005'), 'secret');
$devis->setAuditPdf('audit.pdf');
$repo = $this->createStub(DevisRepository::class);
$repo->method('find')->willReturn($devis);
$controller = new DevisPdfController();
$controller->setContainer($this->createContainer());
$response = $controller(1, 'audit', $repo, $tmpDir);
$this->assertSame(200, $response->getStatusCode());
@unlink($tmpDir.'/var/uploads/devis/audit.pdf');
@rmdir($tmpDir.'/var/uploads/devis');
@rmdir($tmpDir.'/var/uploads');
@rmdir($tmpDir.'/var');
@rmdir($tmpDir);
}
public function testAccessAsNonEmploye(): void
{
$tmpDir = sys_get_temp_dir().'/devis_test_'.uniqid();
mkdir($tmpDir.'/var/uploads/devis', 0775, true);
file_put_contents($tmpDir.'/var/uploads/devis/test.pdf', '%PDF');
$devis = new Devis(new OrderNumber('042026-00006'), 'secret');
$devis->setUnsignedPdf('test.pdf');
$repo = $this->createStub(DevisRepository::class);
$repo->method('find')->willReturn($devis);
$controller = new DevisPdfController();
$controller->setContainer($this->createContainer(false));
$response = $controller(1, 'unsigned', $repo, $tmpDir);
$this->assertSame(200, $response->getStatusCode());
@unlink($tmpDir.'/var/uploads/devis/test.pdf');
@rmdir($tmpDir.'/var/uploads/devis');
@rmdir($tmpDir.'/var/uploads');
@rmdir($tmpDir.'/var');
@rmdir($tmpDir);
}
public function testDefaultTypeNull(): void
{
$devis = new Devis(new OrderNumber('04/2026-00007'), 'secret');
$repo = $this->createStub(DevisRepository::class);
$repo->method('find')->willReturn($devis);
$controller = new DevisPdfController();
$controller->setContainer($this->createContainer());
$this->expectException(NotFoundHttpException::class);
$controller(1, 'unknown', $repo, '/tmp');
}
}