Add audit functionality for AccompanyingPeriod actions

- Integrated `TriggerAuditInterface` in `AccompanyingCourseApiController` to handle audit events.
- Added audit triggers for participation, requestor, confidentiality, and intensity actions using translatable descriptions.
- Updated French translations to include new audit-related messages.
This commit is contained in:
2026-02-27 14:45:25 +01:00
parent 99be7d9614
commit 96b690b75b
3 changed files with 85 additions and 2 deletions

View File

@@ -11,7 +11,9 @@ 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 Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Serializer\Model\Collection;
@@ -39,6 +41,7 @@ use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Serializer\Exception\RuntimeException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Component\Validator\ConstraintViolationList;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
@@ -46,7 +49,16 @@ use Symfony\Component\Workflow\Registry;
final class AccompanyingCourseApiController extends ApiController
{
public function __construct(private readonly AccompanyingPeriodRepository $accompanyingPeriodRepository, private readonly EventDispatcherInterface $eventDispatcher, private readonly ReferralsSuggestionInterface $referralAvailable, private readonly Registry $registry, private readonly ValidatorInterface $validator, private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry, private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository) {}
public function __construct(
private readonly AccompanyingPeriodRepository $accompanyingPeriodRepository,
private readonly EventDispatcherInterface $eventDispatcher,
private readonly ReferralsSuggestionInterface $referralAvailable,
private readonly Registry $registry,
private readonly ValidatorInterface $validator,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
private readonly AccompanyingPeriodWorkRepository $accompanyingPeriodWorkRepository,
private readonly TriggerAuditInterface $triggerAudit,
) {}
public function commentApi($id, Request $request, string $_format): Response
{
@@ -131,7 +143,7 @@ final class AccompanyingCourseApiController extends ApiController
/**
* @ParamConverter("person", options={"id": "person_id"})
*/
public function getAccompanyingPeriodsByPerson(Person $person)
public function getAccompanyingPeriodsByPerson(Person $person): JsonResponse
{
$accompanyingPeriods = $person->getCurrentAccompanyingPeriods();
$accompanyingPeriodsChecked = array_filter(
@@ -172,6 +184,24 @@ final class AccompanyingCourseApiController extends ApiController
$this->managerRegistry->getManager()->flush();
if (AccompanyingPeriod::STEP_DRAFT !== $accompanyingPeriod->getStep()) {
if (Request::METHOD_POST === $request->getMethod()) {
$this->triggerAudit->triggerAudit(
AuditTrail::AUDIT_UPDATE,
$accompanyingPeriod,
description: new TranslatableMessage('audit.accompanying_period.add_participation'),
metadata: ['person_id' => $participation->getPerson()->getId()],
);
} else {
$this->triggerAudit->triggerAudit(
AuditTrail::AUDIT_DELETE,
$accompanyingPeriod,
description: new TranslatableMessage('audit.accompanying_period.remove_participation'),
metadata: ['person_id' => $participation->getPerson()->getId()],
);
}
}
return $this->json($participation, 200, [], ['groups' => ['read']]);
}
@@ -220,6 +250,24 @@ final class AccompanyingCourseApiController extends ApiController
$this->managerRegistry->getManager()->flush();
if (AccompanyingPeriod::STEP_DRAFT !== $accompanyingPeriod->getStep()) {
if (Request::METHOD_POST === $request->getMethod()) {
$this->triggerAudit->triggerAudit(
AuditTrail::AUDIT_UPDATE,
$accompanyingPeriod,
description: new TranslatableMessage('audit.accompanying_period.set_requestor'),
metadata: ['t' => $accompanyingPeriod->getRequestorKind(), 'requestor' => $accompanyingPeriod->getRequestor()->getId()],
);
} else {
$this->triggerAudit->triggerAudit(
AuditTrail::AUDIT_DELETE,
$accompanyingPeriod,
description: new TranslatableMessage('audit.accompanying_period.remove_requestor'),
metadata: ['t' => $accompanyingPeriod->getRequestorKind(), 'requestor' => $accompanyingPeriod->getRequestor()->getId()],
);
}
}
return $this->json($accompanyingPeriod->getRequestor(), 200, [], ['groups' => ['read']]);
}
@@ -283,6 +331,17 @@ final class AccompanyingCourseApiController extends ApiController
$accompanyingCourse->setConfidential(!$accompanyingCourse->isConfidential());
$this->managerRegistry->getManager()->flush();
if (AccompanyingPeriod::STEP_DRAFT !== $accompanyingCourse->getStep()) {
$this->triggerAudit->triggerAudit(
AuditTrail::AUDIT_UPDATE,
$accompanyingCourse,
description: $accompanyingCourse->isConfidential() ?
new TranslatableMessage('audit.accompanying_period.set_confidential') :
new TranslatableMessage('audit.accompanying_period.remove_confidential'),
metadata: ['is_confidential' => $accompanyingCourse->isConfidential()],
);
}
}
return $this->json($accompanyingCourse->isConfidential(), Response::HTTP_OK, [], ['groups' => ['read']]);
@@ -300,6 +359,16 @@ final class AccompanyingCourseApiController extends ApiController
$status = 'regular' === $accompanyingCourse->getIntensity() ? 'occasional' : 'regular';
$accompanyingCourse->setIntensity($status);
$this->managerRegistry->getManager()->flush();
if (AccompanyingPeriod::STEP_DRAFT !== $accompanyingCourse->getStep()) {
$this->triggerAudit->triggerAudit(
AuditTrail::AUDIT_UPDATE,
$accompanyingCourse,
description:
new TranslatableMessage('audit.accompanying_period.set_intensity', ['intensity' => $accompanyingCourse->getIntensity()]),
metadata: ['intensity' => $accompanyingCourse->getIntensity()],
);
}
}
return $this->json($accompanyingCourse->getIntensity(), Response::HTTP_OK, [], ['groups' => ['read']]);

View File

@@ -218,3 +218,11 @@ audit:
Composition n°{id} du {from, date, long} (toujours active)
unknown_composition: >-
Composition inconnue avec identifiant {id}
accompanying_period:
set_intensity: >-
Intensité modifiée à {intensity, select,
occasional {occasionnel}
regular {régulier}
other {inconnu}
}

View File

@@ -1580,6 +1580,12 @@ audit:
person_not_found_with_id: "Personne inconnue avec l'identifiant {id}"
accompanying_period:
accompanying_period_number: "Parcours n°{id}"
add_participation: 'Ajout d''une participation'
remove_participation: 'Suppression d''une participation'
set_requestor: 'Ajout d''un référent'
remove_requestor: 'Suppression d''un référent'
set_confidential: 'Indique parcours comme confidentiel'
remove_confidential: 'Indique parcours comme non-confidentiel'
accompanying_period_work:
accompanying_period_work_number: "Action d'accompagnement n°{id}"
person_resource: