diff --git a/src/Bundle/ChillPersonBundle/Audit/Displayer/CommentSubjectDisplayer.php b/src/Bundle/ChillPersonBundle/Audit/Displayer/CommentSubjectDisplayer.php new file mode 100644 index 000000000..5e61d4b0c --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Audit/Displayer/CommentSubjectDisplayer.php @@ -0,0 +1,33 @@ +type; + } + + public function display(Subject $subject, string $format = 'html', array $options = []): string + { + return $this->translator->trans('audit.accompanying_period_comment.comment_number', ['{id}' => $subject->identifiers['id']]); + } +} diff --git a/src/Bundle/ChillPersonBundle/Audit/SubjectConverter/CommentSubjectConverter.php b/src/Bundle/ChillPersonBundle/Audit/SubjectConverter/CommentSubjectConverter.php new file mode 100644 index 000000000..108d472a8 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Audit/SubjectConverter/CommentSubjectConverter.php @@ -0,0 +1,50 @@ + + */ +class CommentSubjectConverter implements SubjectConverterInterface, SubjectConverterManagerAwareInterface +{ + use SubjectConverterManagerAwareTrait; + + public function convert(mixed $subject, bool $includeAssociated = false): SubjectBag + { + \assert($subject instanceof Comment); + + $main = new SubjectBag(new Subject('accompanying_period_comment', ['id' => $subject->getId()])); + + if (null !== $subject->getAccompanyingPeriod()) { + $main->append($this->subjectConverterManager->getSubjectsForEntity($subject->getAccompanyingPeriod(), false)); + } + + return $main; + } + + public function supportsConvert(mixed $subject): bool + { + return $subject instanceof Comment; + } + + public static function getDefaultPriority(): int + { + return 0; + } +} diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php index f7622953d..b40a4f357 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseCommentController.php @@ -11,6 +11,8 @@ declare(strict_types=1); namespace Chill\PersonBundle\Controller; +use Chill\MainBundle\Audit\TriggerAuditInterface; +use Chill\MainBundle\Entity\AuditTrail; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Form\AccompanyingCourseCommentType; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter; @@ -27,6 +29,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Translation\TranslatableMessage; use Symfony\Contracts\Translation\TranslatorInterface; class AccompanyingCourseCommentController extends AbstractController @@ -36,6 +39,7 @@ class AccompanyingCourseCommentController extends AbstractController private readonly FormFactoryInterface $formFactory, private readonly TranslatorInterface $translator, private readonly ManagerRegistry $managerRegistry, + private readonly TriggerAuditInterface $triggerAudit, ) {} /** @@ -48,6 +52,12 @@ class AccompanyingCourseCommentController extends AbstractController { $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE_DETAILS, $accompanyingCourse); + $this->triggerAudit->triggerAudit( + AuditTrail::AUDIT_LIST, + $accompanyingCourse, + description: new TranslatableMessage('audit.accompanying_period_comment.list') + ); + $em = $this->managerRegistry->getManager(); $afterSuccessfulRedirectResponse = $this->redirectToRoute('chill_person_accompanying_period_comment_list', [ 'accompanying_period_id' => $accompanyingCourse->getId(), @@ -84,6 +94,8 @@ class AccompanyingCourseCommentController extends AbstractController if ($editForm->isSubmitted() && $editForm->isValid()) { $em->flush(); + $this->triggerAudit->triggerAudit(AuditTrail::AUDIT_UPDATE, $commentEdited); + return $afterSuccessfulRedirectResponse; } @@ -103,6 +115,8 @@ class AccompanyingCourseCommentController extends AbstractController $em->persist($newComment); $em->flush(); + $this->triggerAudit->triggerAudit(AuditTrail::AUDIT_CREATE, $newComment); + return $afterSuccessfulRedirectResponse; } } @@ -129,6 +143,8 @@ class AccompanyingCourseCommentController extends AbstractController $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { + $this->triggerAudit->triggerAudit(AuditTrail::AUDIT_DELETE, $comment); + $this->entityManager->remove($comment); if ($comment->getAccompanyingPeriod()->getPinnedComment() === $comment) { @@ -163,6 +179,12 @@ class AccompanyingCourseCommentController extends AbstractController $this->managerRegistry->getManager()->flush(); + $this->triggerAudit->triggerAudit( + AuditTrail::AUDIT_UPDATE, + $comment, + description: new TranslatableMessage('audit.accompanying_period_comment.pin') + ); + $this->addFlash('success', $this->translator->trans('accompanying_course.comment is pinned')); return $this->redirectToRoute('chill_person_accompanying_period_comment_list', [ @@ -179,6 +201,12 @@ class AccompanyingCourseCommentController extends AbstractController $this->managerRegistry->getManager()->flush(); + $this->triggerAudit->triggerAudit( + AuditTrail::AUDIT_UPDATE, + $comment, + description: new TranslatableMessage('audit.accompanying_period_comment.unpin') + ); + $this->addFlash('success', $this->translator->trans('accompanying_course.comment is unpinned')); return $this->redirectToRoute('chill_person_accompanying_period_comment_list', [ diff --git a/src/Bundle/ChillPersonBundle/Tests/Audit/SubjectConverter/CommentSubjectConverterTest.php b/src/Bundle/ChillPersonBundle/Tests/Audit/SubjectConverter/CommentSubjectConverterTest.php new file mode 100644 index 000000000..0b27594bf --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Audit/SubjectConverter/CommentSubjectConverterTest.php @@ -0,0 +1,70 @@ +converter = new CommentSubjectConverter(); + } + + public function testSupportsConvert(): void + { + $this->assertTrue($this->converter->supportsConvert($this->prophesize(Comment::class)->reveal())); + $this->assertFalse($this->converter->supportsConvert(new \stdClass())); + } + + public function testConvert(): void + { + $comment = $this->prophesize(Comment::class); + $comment->getId()->willReturn(456); + + $accompanyingPeriod = $this->prophesize(AccompanyingPeriod::class); + $comment->getAccompanyingPeriod()->willReturn($accompanyingPeriod->reveal()); + + $subjectConverterManager = $this->prophesize(SubjectConverterManagerInterface::class); + $accompanyingPeriodSubject = new Subject('accompanying_period', ['id' => 123]); + $accompanyingPeriodSubjectBag = new SubjectBag($accompanyingPeriodSubject); + + $subjectConverterManager->getSubjectsForEntity($accompanyingPeriod->reveal(), false) + ->willReturn($accompanyingPeriodSubjectBag); + + $this->converter->setSubjectConverterManager($subjectConverterManager->reveal()); + + $result = $this->converter->convert($comment->reveal()); + + $this->assertSame('accompanying_period_comment', $result->subject->type); + $this->assertSame(['id' => 456], $result->subject->identifiers); + + $this->assertCount(1, $result->associatedSubjects); + $this->assertSame($accompanyingPeriodSubject, $result->associatedSubjects[0]); + } +} diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 656a7d991..6e43a7d77 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1608,3 +1608,8 @@ audit: household_member: not_found_with_id: 'Membre du ménage non trouvé avec identifiant {id}' member_in_household: 'membre du ménage' + accompanying_period_comment: + comment_number: "Commentaire n°{id}" + list: "Liste des commentaires d'un parcours" + pin: "Commentaire épinglé" + unpin: "Commentaire désépinglé"