diff --git a/src/Bundle/ChillMainBundle/Audit/Converter/ExportGenerationSubjectConverter.php b/src/Bundle/ChillMainBundle/Audit/Converter/ExportGenerationSubjectConverter.php new file mode 100644 index 000000000..a1b2803be --- /dev/null +++ b/src/Bundle/ChillMainBundle/Audit/Converter/ExportGenerationSubjectConverter.php @@ -0,0 +1,37 @@ + $subject->getId(), 'alias' => $subject->getExportAlias()])); + } + + public function supportsConvert(mixed $subject): bool + { + return $subject instanceof ExportGeneration; + } + + public static function getDefaultPriority(): int + { + return 0; + } +} diff --git a/src/Bundle/ChillMainBundle/Audit/Displayer/ExportGenerationSubjectDisplayer.php b/src/Bundle/ChillMainBundle/Audit/Displayer/ExportGenerationSubjectDisplayer.php new file mode 100644 index 000000000..b06662ea1 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Audit/Displayer/ExportGenerationSubjectDisplayer.php @@ -0,0 +1,49 @@ +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 ''.$msg.''; + } + + return $msg; + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Audit/Converter/ExportGenerationSubjectConverterTest.php b/src/Bundle/ChillMainBundle/Tests/Audit/Converter/ExportGenerationSubjectConverterTest.php new file mode 100644 index 000000000..92467cb6a --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Audit/Converter/ExportGenerationSubjectConverterTest.php @@ -0,0 +1,73 @@ +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()); + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Audit/Displayer/ExportGenerationSubjectDisplayerTest.php b/src/Bundle/ChillMainBundle/Tests/Audit/Displayer/ExportGenerationSubjectDisplayerTest.php new file mode 100644 index 000000000..8acb7594a --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Audit/Displayer/ExportGenerationSubjectDisplayerTest.php @@ -0,0 +1,142 @@ +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('Translated Msg', $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 '); + + $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('Export with title '.$escapedTitle.'', $result); + } +} diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index fece175c6..f7ac4e306 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -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 }}"