From 5eaf3ee82845f9403f023861cfd3d6eff868051d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 26 Feb 2026 16:00:41 +0100 Subject: [PATCH] Add audit functionality to `HouseholdController`, `RelationApiController`, and repository methods - Integrated `TriggerAuditInterface` in `HouseholdController` and added audit triggers for view and update actions. - Added onAfterFlush audit handling in `RelationApiController` to support create, update, and delete events. - Updated `HouseholdMembersRepository` with a `find` method for retrieving `HouseholdMember` entities. --- .../Controller/HouseholdController.php | 32 ++++++++++++++++++- .../Controller/PersonController.php | 3 -- .../Controller/RelationApiController.php | 25 ++++++++++++++- .../Household/HouseholdMembersRepository.php | 5 +++ .../translations/messages.fr.yml | 15 +++++++++ 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php index d63c5aea9..cc30815d7 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php @@ -11,7 +11,9 @@ declare(strict_types=1); namespace Chill\PersonBundle\Controller; +use Chill\MainBundle\Audit\TriggerAuditInterface; use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Entity\AuditTrail; use Chill\MainBundle\Form\Type\AddressDateType; use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Form\HouseholdType; @@ -27,12 +29,20 @@ use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Security; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Translation\TranslatableMessage; use Symfony\Contracts\Translation\TranslatorInterface; #[Route(path: '/{_locale}/person/household')] class HouseholdController extends AbstractController { - public function __construct(private readonly TranslatorInterface $translator, private readonly PositionRepository $positionRepository, private readonly SerializerInterface $serializer, private readonly Security $security, private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry) {} + public function __construct( + private readonly TranslatorInterface $translator, + private readonly PositionRepository $positionRepository, + private readonly SerializerInterface $serializer, + private readonly Security $security, + private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry, + private readonly TriggerAuditInterface $triggerAudit, + ) {} /** * @ParamConverter("household", options={"id": "household_id"}) @@ -40,6 +50,8 @@ class HouseholdController extends AbstractController #[Route(path: '/{household_id}/accompanying-period', name: 'chill_person_household_accompanying_period', methods: ['GET', 'HEAD'])] public function accompanyingPeriod(Request $request, Household $household) { + ($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $household, description: new TranslatableMessage('audit.household.list_accompanying_periods')); + $currentMembers = $household->getCurrentPersons(); $accompanyingPeriods = []; @@ -90,6 +102,8 @@ class HouseholdController extends AbstractController #[Route(path: '/{household_id}/address/edit', name: 'chill_person_household_address_edit', methods: ['GET', 'HEAD', 'POST'])] public function addressEdit(Request $request, Household $household) { + ($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $household, description: new TranslatableMessage('audit.household.edit_address_page')); + // TODO ACL $address_id = $request->query->get('address_id'); @@ -112,6 +126,8 @@ class HouseholdController extends AbstractController #[Route(path: '/{household_id}/addresses', name: 'chill_person_household_addresses', methods: ['GET', 'HEAD'])] public function addresses(Request $request, Household $household) { + ($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $household, description: new TranslatableMessage('audit.household.list_addresses')); + // TODO ACL // TODO put these lines into a validator constraint on household->getAddress @@ -138,6 +154,8 @@ class HouseholdController extends AbstractController #[Route(path: '/{household_id}/address/move', name: 'chill_person_household_address_move', methods: ['GET', 'HEAD', 'POST'])] public function addressMove(Request $request, Household $household) { + ($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $household, description: new TranslatableMessage('audit.household.address_move')); + // TODO ACL return $this->render( @@ -154,6 +172,8 @@ class HouseholdController extends AbstractController #[Route(path: '/{household_id}/address/edit_valid_from', name: 'chill_person_household_address_valid_from_edit', methods: ['GET', 'HEAD', 'POST'])] public function addressValidFromEdit(Request $request, Household $household) { + ($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $household); + $this->denyAccessUnlessGranted(HouseholdVoter::EDIT, $household); if (!$request->query->has('address_id')) { @@ -183,6 +203,8 @@ class HouseholdController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { $household->makeAddressConsistent(); + ($this->triggerAudit)(AuditTrail::AUDIT_UPDATE, $household, description: new TranslatableMessage('audit.household.address_valid_from_edit')); + $this->managerRegistry->getManager()->flush(); return $this->redirectToRoute('chill_person_household_addresses', [ @@ -206,12 +228,16 @@ class HouseholdController extends AbstractController #[Route(path: '/{household_id}/members/metadata/edit', name: 'chill_person_household_members_metadata_edit', methods: ['GET', 'POST'])] public function editHouseholdMetadata(Request $request, Household $household) { + ($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $household); + // TODO ACL $form = $this->createMetadataForm($household); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { + ($this->triggerAudit)(AuditTrail::AUDIT_UPDATE, $household, description: new TranslatableMessage('audit.household.members_metadata_edit')); + $this->managerRegistry->getManager()->flush(); $this->addFlash('success', $this->translator->trans('household.data_saved')); @@ -239,6 +265,8 @@ class HouseholdController extends AbstractController #[Route(path: '/{household_id}/relationship', name: 'chill_person_household_relationship', methods: ['GET', 'HEAD'])] public function showRelationship(Request $request, Household $household) { + ($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $household, description: new TranslatableMessage('audit.household.relationship')); + $jsonString = $this->serializer->serialize( $household->getCurrentPersons(), 'json', @@ -260,6 +288,8 @@ class HouseholdController extends AbstractController #[Route(path: '/{household_id}/summary', name: 'chill_person_household_summary', methods: ['GET', 'HEAD'])] public function summary(Request $request, Household $household) { + ($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $household, description: new TranslatableMessage('audit.household.summary')); + // TODO ACL $positions = $this->positionRepository diff --git a/src/Bundle/ChillPersonBundle/Controller/PersonController.php b/src/Bundle/ChillPersonBundle/Controller/PersonController.php index 545902e6f..f9e0786be 100644 --- a/src/Bundle/ChillPersonBundle/Controller/PersonController.php +++ b/src/Bundle/ChillPersonBundle/Controller/PersonController.php @@ -19,7 +19,6 @@ use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Household\HouseholdMember; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Form\CreationPersonType; -use Chill\PersonBundle\Privacy\PrivacyEvent; use Chill\PersonBundle\Repository\PersonRepository; use Chill\PersonBundle\Search\SimilarPersonMatcher; use Chill\PersonBundle\Security\Authorization\PersonVoter; @@ -78,8 +77,6 @@ final class PersonController extends AbstractController 'You are not allowed to see this person.' ); - $event = new PrivacyEvent($person); - $this->eventDispatcher->dispatch($event, PrivacyEvent::PERSON_PRIVACY_EVENT); ($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $person, description: new TranslatableMessage('audit.household.list_person_file')); return $this->render( diff --git a/src/Bundle/ChillPersonBundle/Controller/RelationApiController.php b/src/Bundle/ChillPersonBundle/Controller/RelationApiController.php index 31eabb54a..7a0773ec3 100644 --- a/src/Bundle/ChillPersonBundle/Controller/RelationApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/RelationApiController.php @@ -11,6 +11,29 @@ declare(strict_types=1); namespace Chill\PersonBundle\Controller; +use Chill\MainBundle\Audit\TriggerAuditInterface; use Chill\MainBundle\CRUD\Controller\ApiController; +use Chill\MainBundle\Entity\AuditTrail; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Validator\ConstraintViolationListInterface; -class RelationApiController extends ApiController {} +class RelationApiController extends ApiController +{ + public function __construct(private TriggerAuditInterface $triggerAudit) {} + + protected function onAfterFlush(string $action, Request $request, string $_format, $entity, ConstraintViolationListInterface $errors, array $more = []): ?Response + { + ($this->triggerAudit)( + match ($action) { + 'create' => AuditTrail::AUDIT_CREATE, + 'update' => AuditTrail::AUDIT_UPDATE, + 'delete' => AuditTrail::AUDIT_DELETE, + default => 'relation.action', + }, + $entity, + ); + + return parent::onAfterFlush($action, $request, $_format, $entity, $errors, $more); + } +} diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdMembersRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdMembersRepository.php index 777b14cdd..37825907b 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdMembersRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdMembersRepository.php @@ -23,4 +23,9 @@ final readonly class HouseholdMembersRepository { $this->repository = $entityManager->getRepository(HouseholdMember::class); } + + public function find($id): ?HouseholdMember + { + return $this->repository->find($id); + } } diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 07a265f85..fe6757ebd 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -1585,3 +1585,18 @@ audit: person_resource: list: Liste des personnes ressources person_resource_number: "Personne ressource n°{id}: {name}" + household: + list_accompanying_periods: "Liste des parcours d'accompagnement du ménage" + edit_address_page: "Édition de l'adresse du ménage" + list_addresses: "Liste des adresses du ménage" + address_move: "Déménagement du ménage" + address_valid_from_edit: "Modification de la date de début de l'adresse du ménage" + members_metadata_edit: "Modification des métadonnées des membres du ménage" + relationship: "Relations du ménage" + summary: "Résumé du ménage" + list_person_file: Liste des ménages d'un usager + edit_participation: "Modification d'une participation au ménage" + household_not_found_with_id: 'Ménage non trouvé avec identifiant {id}' + household_member: + not_found_with_id: 'Membre du ménage non trouvé avec identifiant {id}' + member_in_household: 'membre du ménage'