Send data dumps as email attachments instead of links, update translations, and add unit tests for the handler.

This commit is contained in:
Julien Fastré 2025-06-26 12:21:19 +02:00
parent 456f00566d
commit 786c60a50d
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
6 changed files with 162 additions and 25 deletions

View File

@ -0,0 +1,6 @@
kind: Fixed
body: 'Doc Generation: the "dump only" method send the document as an email attachment.'
time: 2025-06-26T12:20:30.083601058+02:00
custom:
Issue: "393"
SchemaChange: No schema change

View File

@ -1,7 +1,5 @@
{{ 'docgen.data_dump_email.Dear'|trans }}
{{ 'docgen.data_dump_email.data_dump_ready_and_link'|trans }}
{{ 'docgen.data_dump_email.data_dump_ready_and_attached'|trans }}
{{ link }}
{{ 'docgen.data_dump_email.link_valid_until'|trans({validity: validity}) }}
{{ 'docgen.data_dump_email.filename'|trans({filename: filename}) }}

View File

@ -11,13 +11,13 @@ declare(strict_types=1);
namespace Chill\DocGeneratorBundle\Service\Messenger;
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository;
use Chill\DocGeneratorBundle\Service\Generator\Generator;
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface;
use Chill\DocGeneratorBundle\Service\Generator\GeneratorException;
use Chill\DocStoreBundle\AsyncUpload\TempUrlGeneratorInterface;
use Chill\DocGeneratorBundle\Service\Generator\GeneratorInterface;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Exception\StoredObjectManagerException;
use Chill\DocStoreBundle\Repository\StoredObjectRepository;
use Chill\DocStoreBundle\Repository\StoredObjectRepositoryInterface;
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
@ -37,15 +37,15 @@ class RequestGenerationHandler implements MessageHandlerInterface
private const LOG_PREFIX = '[docgen message handler] ';
public function __construct(
private readonly DocGeneratorTemplateRepository $docGeneratorTemplateRepository,
private readonly DocGeneratorTemplateRepositoryInterface $docGeneratorTemplateRepository,
private readonly EntityManagerInterface $entityManager,
private readonly Generator $generator,
private readonly GeneratorInterface $generator,
private readonly LoggerInterface $logger,
private readonly StoredObjectRepository $storedObjectRepository,
private readonly StoredObjectRepositoryInterface $storedObjectRepository,
private readonly UserRepositoryInterface $userRepository,
private readonly MailerInterface $mailer,
private readonly TempUrlGeneratorInterface $tempUrlGenerator,
private readonly TranslatorInterface $translator,
private readonly StoredObjectManagerInterface $storedObjectManager,
) {}
public function __invoke(RequestGenerationMessage $message)
@ -90,7 +90,7 @@ class RequestGenerationHandler implements MessageHandlerInterface
$this->sendDataDump($destinationStoredObject, $message);
} else {
$destinationStoredObject = $this->generator->generateDocFromTemplate(
$this->generator->generateDocFromTemplate(
$template,
$message->getEntityId(),
$message->getContextGenerationData(),
@ -122,19 +122,20 @@ class RequestGenerationHandler implements MessageHandlerInterface
private function sendDataDump(StoredObject $destinationStoredObject, RequestGenerationMessage $message): void
{
$url = $this->tempUrlGenerator->generate('GET', $destinationStoredObject->getFilename(), 3600);
$parts = [];
parse_str(parse_url($url->url)['query'], $parts);
$validity = \DateTimeImmutable::createFromFormat('U', $parts['temp_url_expires']);
// Get the content of the document
$content = $this->storedObjectManager->read($destinationStoredObject);
$filename = $destinationStoredObject->getFilename();
$contentType = $destinationStoredObject->getType();
// Create the email with the document as an attachment
$email = (new TemplatedEmail())
->to($message->getSendResultToEmail())
->textTemplate('@ChillDocGenerator/Email/send_data_dump_to_admin.txt.twig')
->context([
'link' => $url->url,
'validity' => $validity,
'filename' => $filename,
])
->subject($this->translator->trans('docgen.data_dump_email.subject'));
->subject($this->translator->trans('docgen.data_dump_email.subject'))
->attach($content, $filename, $contentType);
$this->mailer->send($email);
}

View File

@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocGeneratorBundle\Tests\Service\Messenger;
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface;
use Chill\DocGeneratorBundle\Service\Generator\GeneratorInterface;
use Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationHandler;
use Chill\DocGeneratorBundle\Service\Messenger\RequestGenerationMessage;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Repository\StoredObjectRepositoryInterface;
use Chill\DocStoreBundle\Service\StoredObjectManagerInterface;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Repository\UserRepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Psr\Log\NullLogger;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @internal
*
* @coversNothing
*/
class RequestGenerationHandlerTest extends TestCase
{
use ProphecyTrait;
public function testGenerationHappyScenario(): void
{
// Create entities
$template = new DocGeneratorTemplate();
$this->setPrivateProperty($template, 'id', 1);
$storedObject = new StoredObject();
$this->setPrivateProperty($storedObject, 'id', 2);
$creator = new User();
$creator->setEmail('test@example.com');
$this->setPrivateProperty($creator, 'id', 3);
$docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class);
$docGeneratorTemplateRepository->find(1)->willReturn($template);
$storedObjectRepository = $this->prophesize(StoredObjectRepositoryInterface::class);
$storedObjectRepository->find(2)->willReturn($storedObject);
$userRepository = $this->prophesize(UserRepositoryInterface::class);
$userRepository->find(3)->willReturn($creator);
// Create a mock for the Query object
$query = $this->prophesize(Query::class);
$query->setParameter('id', 2)->willReturn($query->reveal());
$query->execute()->shouldBeCalled();
// Create a mock for the EntityManager
$entityManager = $this->prophesize(EntityManagerInterface::class);
$entityManager->createQuery(Argument::containingString('UPDATE'))->willReturn($query->reveal());
$entityManager->flush()->shouldBeCalled();
$generator = $this->prophesize(GeneratorInterface::class);
$generator->generateDocFromTemplate(
$template,
123, // entityId
['key' => 'value'], // contextGenerationData
$storedObject,
$creator
)
->willReturn($storedObject)->shouldBeCalled();
$logger = new NullLogger();
$mailer = $this->prophesize(MailerInterface::class);
$translator = $this->prophesize(TranslatorInterface::class);
$storedObjectManager = $this->prophesize(StoredObjectManagerInterface::class);
// Create handler
$handler = new RequestGenerationHandler(
$docGeneratorTemplateRepository->reveal(),
$entityManager->reveal(),
$generator->reveal(),
$logger,
$storedObjectRepository->reveal(),
$userRepository->reveal(),
$mailer->reveal(),
$translator->reveal(),
$storedObjectManager->reveal()
);
// Create message
$message = new RequestGenerationMessage(
$creator,
$template,
123, // entityId
$storedObject,
['key' => 'value'], // contextGenerationData
false, // isTest
null, // sendResultToEmail
false // dumpOnly
);
// Invoke handler
$handler->__invoke($message);
// Assertions
// The assertions are handled by the shouldBeCalled() expectations on the mocks
$this->assertTrue(true); // Just to have an assertion in the test
}
private function setPrivateProperty(object $object, string $propertyName, $value): void
{
$reflection = new \ReflectionClass($object);
$property = $reflection->getProperty($propertyName);
$property->setAccessible(true);
$property->setValue($object, $value);
}
}

View File

@ -1,4 +1,2 @@
docgen:
data_dump_email:
link_valid_until: >-
Ce lien est valide jusqu'au {validity, date, full}, {validity, time, medium}
# No ICU messages needed for data_dump_email anymore

View File

@ -34,8 +34,10 @@ docgen:
data_dump_email:
subject: Contenu des données de génération de document disponible
Dear: Cher
data_dump_ready_and_link: >-
Le contenu des données est disponible. Vous pouvez le télécharger à l'aide du lien suivant:
data_dump_ready_and_attached: >-
Le contenu des données est disponible. Vous le trouverez en pièce jointe à cet email.
filename: >-
Nom du fichier: %filename%