mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2026-04-04 12:03:44 +00:00
Add support for audit display and conversion of ExportGeneration entities
- Introduced `ExportGenerationSubjectConverter` for converting `ExportGeneration` entities into audit subjects. - Added `ExportGenerationSubjectDisplayer` for translating and displaying `ExportGeneration` audit subjects. - Included new translation keys for `ExportGeneration` display messages. - Implemented comprehensive unit tests for both the converter and displayer to ensure reliability.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
<?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\MainBundle\Audit\Converter;
|
||||
|
||||
use Chill\MainBundle\Audit\Subject;
|
||||
use Chill\MainBundle\Audit\SubjectBag;
|
||||
use Chill\MainBundle\Audit\SubjectConverterInterface;
|
||||
use Chill\MainBundle\Entity\ExportGeneration;
|
||||
|
||||
class ExportGenerationSubjectConverter implements SubjectConverterInterface
|
||||
{
|
||||
public function convert(mixed $subject, bool $includeAssociated = false): SubjectBag
|
||||
{
|
||||
\assert($subject instanceof ExportGeneration);
|
||||
|
||||
return new SubjectBag(new Subject('export_generation', ['id' => $subject->getId(), 'alias' => $subject->getExportAlias()]));
|
||||
}
|
||||
|
||||
public function supportsConvert(mixed $subject): bool
|
||||
{
|
||||
return $subject instanceof ExportGeneration;
|
||||
}
|
||||
|
||||
public static function getDefaultPriority(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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\MainBundle\Audit\Displayer;
|
||||
|
||||
use Chill\MainBundle\Audit\Subject;
|
||||
use Chill\MainBundle\Audit\SubjectDisplayerInterface;
|
||||
use Chill\MainBundle\Repository\ExportGenerationRepository;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
final readonly class ExportGenerationSubjectDisplayer implements SubjectDisplayerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private ExportGenerationRepository $exportGenerationRepository,
|
||||
private TranslatorInterface $translator,
|
||||
) {}
|
||||
|
||||
public function supportsDisplay(Subject $subject, array $options = []): bool
|
||||
{
|
||||
return 'export_generation' === $subject->type;
|
||||
}
|
||||
|
||||
public function display(Subject $subject, string $format = 'html', array $options = []): string
|
||||
{
|
||||
$export = $this->exportGenerationRepository->find($subject->identifiers['id']);
|
||||
|
||||
$msg = match (null === $export || '' === $export->getStoredObject()->getTitle()) {
|
||||
true => $this->translator->trans('audit.export_generation.display_without_entity', ['{{ id }}' => $subject->identifiers['id']]),
|
||||
false => $this->translator->trans('audit.export_generation.display_with_entity', [
|
||||
'{{ id }}' => $subject->identifiers['id'],
|
||||
'{{ title }}' => 'html' === $format ? htmlspecialchars($export->getStoredObject()->getTitle()) : $export->getStoredObject()->getTitle(),
|
||||
]),
|
||||
};
|
||||
|
||||
if ('html' === $format) {
|
||||
return '<span>'.$msg.'</span>';
|
||||
}
|
||||
|
||||
return $msg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?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\MainBundle\Tests\Audit\Converter;
|
||||
|
||||
use Chill\MainBundle\Audit\Converter\ExportGenerationSubjectConverter;
|
||||
use Chill\MainBundle\Entity\ExportGeneration;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class ExportGenerationSubjectConverterTest extends TestCase
|
||||
{
|
||||
private ExportGenerationSubjectConverter $converter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->converter = new ExportGenerationSubjectConverter();
|
||||
}
|
||||
|
||||
public function testSupportsConvert(): void
|
||||
{
|
||||
$exportGeneration = $this->createMock(ExportGeneration::class);
|
||||
$this->assertTrue($this->converter->supportsConvert($exportGeneration));
|
||||
|
||||
$this->assertFalse($this->converter->supportsConvert(new \stdClass()));
|
||||
}
|
||||
|
||||
public function testConvert(): void
|
||||
{
|
||||
$exportAlias = 'my_export_alias';
|
||||
$exportGeneration = new ExportGeneration($exportAlias);
|
||||
$id = $exportGeneration->getId();
|
||||
|
||||
$subjectBag = $this->converter->convert($exportGeneration);
|
||||
|
||||
$subject = $subjectBag->subject;
|
||||
$this->assertSame('export_generation', $subject->type);
|
||||
$this->assertSame($id, $subject->identifiers['id']);
|
||||
$this->assertSame($exportAlias, $subject->identifiers['alias']);
|
||||
}
|
||||
|
||||
public function testConvertWithIncludeAssociated(): void
|
||||
{
|
||||
$exportAlias = 'my_export_alias';
|
||||
$exportGeneration = new ExportGeneration($exportAlias);
|
||||
$id = $exportGeneration->getId();
|
||||
|
||||
$subjectBag = $this->converter->convert($exportGeneration, true);
|
||||
|
||||
$subject = $subjectBag->subject;
|
||||
$this->assertSame('export_generation', $subject->type);
|
||||
$this->assertSame($id, $subject->identifiers['id']);
|
||||
$this->assertSame($exportAlias, $subject->identifiers['alias']);
|
||||
$this->assertEmpty($subjectBag->associatedSubjects);
|
||||
}
|
||||
|
||||
public function testGetDefaultPriority(): void
|
||||
{
|
||||
$this->assertSame(0, ExportGenerationSubjectConverter::getDefaultPriority());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?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\MainBundle\Tests\Audit\Displayer;
|
||||
|
||||
use Chill\MainBundle\Audit\Displayer\ExportGenerationSubjectDisplayer;
|
||||
use Chill\MainBundle\Audit\Subject;
|
||||
use Chill\MainBundle\Entity\ExportGeneration;
|
||||
use Chill\MainBundle\Repository\ExportGenerationRepository;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class ExportGenerationSubjectDisplayerTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
private $exportGenerationRepository;
|
||||
private $translator;
|
||||
private ExportGenerationSubjectDisplayer $displayer;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->exportGenerationRepository = $this->prophesize(ExportGenerationRepository::class);
|
||||
$this->translator = $this->prophesize(TranslatorInterface::class);
|
||||
$this->displayer = new ExportGenerationSubjectDisplayer(
|
||||
$this->exportGenerationRepository->reveal(),
|
||||
$this->translator->reveal()
|
||||
);
|
||||
}
|
||||
|
||||
public function testSupportsDisplay(): void
|
||||
{
|
||||
$subject = new Subject('export_generation', ['id' => 'foo']);
|
||||
$this->assertTrue($this->displayer->supportsDisplay($subject));
|
||||
|
||||
$otherSubject = new Subject('other', ['id' => 'foo']);
|
||||
$this->assertFalse($this->displayer->supportsDisplay($otherSubject));
|
||||
}
|
||||
|
||||
public function testDisplayWithEntityNotFound(): void
|
||||
{
|
||||
$id = '550e8400-e29b-41d4-a716-446655440000';
|
||||
$subject = new Subject('export_generation', ['id' => $id]);
|
||||
|
||||
$this->exportGenerationRepository->find($id)->willReturn(null);
|
||||
|
||||
$this->translator->trans('audit.export_generation.display_without_entity', ['{{ id }}' => $id])
|
||||
->willReturn('Export not found '.$id);
|
||||
|
||||
$result = $this->displayer->display($subject, 'text');
|
||||
|
||||
$this->assertSame('Export not found '.$id, $result);
|
||||
}
|
||||
|
||||
public function testDisplayWithEntityFound(): void
|
||||
{
|
||||
$id = '550e8400-e29b-41d4-a716-446655440000';
|
||||
$subject = new Subject('export_generation', ['id' => $id]);
|
||||
|
||||
$exportGeneration = new ExportGeneration('my_alias');
|
||||
$exportGeneration->getStoredObject()->setTitle('My Export Title');
|
||||
|
||||
$this->exportGenerationRepository->find($id)->willReturn($exportGeneration);
|
||||
|
||||
$this->translator->trans('audit.export_generation.display_with_entity', [
|
||||
'{{ id }}' => $id,
|
||||
'{{ title }}' => 'My Export Title',
|
||||
])->willReturn('Export '.$id.' with title My Export Title');
|
||||
|
||||
$result = $this->displayer->display($subject, 'text');
|
||||
|
||||
$this->assertSame('Export '.$id.' with title My Export Title', $result);
|
||||
}
|
||||
|
||||
public function testDisplayWithEmptyTitle(): void
|
||||
{
|
||||
$id = '550e8400-e29b-41d4-a716-446655440000';
|
||||
$subject = new Subject('export_generation', ['id' => $id]);
|
||||
|
||||
$exportGeneration = new ExportGeneration('my_alias');
|
||||
$exportGeneration->getStoredObject()->setTitle('');
|
||||
|
||||
$this->exportGenerationRepository->find($id)->willReturn($exportGeneration);
|
||||
|
||||
$this->translator->trans('audit.export_generation.display_without_entity', ['{{ id }}' => $id])
|
||||
->willReturn('Export not found '.$id);
|
||||
|
||||
$result = $this->displayer->display($subject, 'text');
|
||||
|
||||
$this->assertSame('Export not found '.$id, $result);
|
||||
}
|
||||
|
||||
public function testDisplayHtmlFormatWrapsInSpan(): void
|
||||
{
|
||||
$id = '550e8400-e29b-41d4-a716-446655440000';
|
||||
$subject = new Subject('export_generation', ['id' => $id]);
|
||||
|
||||
$this->exportGenerationRepository->find($id)->willReturn(null);
|
||||
|
||||
$this->translator->trans('audit.export_generation.display_without_entity', ['{{ id }}' => $id])
|
||||
->willReturn('Translated Msg');
|
||||
|
||||
$result = $this->displayer->display($subject, 'html');
|
||||
|
||||
$this->assertSame('<span>Translated Msg</span>', $result);
|
||||
}
|
||||
|
||||
public function testDisplayHtmlFormatEscapesTitle(): void
|
||||
{
|
||||
$id = '550e8400-e29b-41d4-a716-446655440000';
|
||||
$subject = new Subject('export_generation', ['id' => $id]);
|
||||
|
||||
$exportGeneration = new ExportGeneration('my_alias');
|
||||
$exportGeneration->getStoredObject()->setTitle('Title with <script>alert("xss")</script>');
|
||||
|
||||
$this->exportGenerationRepository->find($id)->willReturn($exportGeneration);
|
||||
|
||||
$escapedTitle = 'Title with <script>alert("xss")</script>';
|
||||
$this->translator->trans('audit.export_generation.display_with_entity', [
|
||||
'{{ id }}' => $id,
|
||||
'{{ title }}' => $escapedTitle,
|
||||
])->willReturn('Export with title '.$escapedTitle);
|
||||
|
||||
$result = $this->displayer->display($subject, 'html');
|
||||
|
||||
$this->assertSame('<span>Export with title '.$escapedTitle.'</span>', $result);
|
||||
}
|
||||
}
|
||||
@@ -1046,3 +1046,8 @@ audit_trail:
|
||||
waiting: En cours de préparation
|
||||
failure: Erreur lors de la préparation du document
|
||||
stopped: La préparation a nécessité une attente trop longue, veuillez recharger la page
|
||||
|
||||
audit:
|
||||
export_generation:
|
||||
display_without_entity: "Génération d'export n°{{ id }}"
|
||||
display_with_entity: "Génération d'export n°{{ id }}: {{ title }}"
|
||||
|
||||
Reference in New Issue
Block a user