Add audit functionality for SingleTask and integrate subject converter and displayer

- Introduced `SingleTaskSubjectConverter` for audit conversion logic and `SingleTaskSubjectDisplayer` for display logic, including a Twig template.
- Integrated `TriggerAuditInterface` into `SingleTaskController` and added audit triggers for create, view, update, delete, and list actions with translatable descriptions.
- Registered new audit-related services in `services.yaml` and loaded `services.yaml` in the extension.
- Created unit tests to validate the behavior of the subject converter and related functionality.
- Added French translations for audit messages related to `SingleTask`.
This commit is contained in:
2026-03-02 15:35:52 +01:00
parent 9da82878af
commit 2313b053d4
8 changed files with 241 additions and 1 deletions

View File

@@ -11,6 +11,8 @@ declare(strict_types=1);
namespace Chill\TaskBundle\Controller;
use Chill\MainBundle\Audit\TriggerAuditInterface;
use Chill\MainBundle\Entity\AuditTrail;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
@@ -60,6 +62,7 @@ final class SingleTaskController extends AbstractController
private readonly SingleTaskRepository $singleTaskRepository,
private readonly Security $security,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
private readonly TriggerAuditInterface $triggerAudit,
) {}
#[Route(path: '/{_locale}/task/single-task/{id}/delete', name: 'chill_task_single_task_delete', methods: ['GET', 'POST', 'DELETE'])]
@@ -113,6 +116,8 @@ final class SingleTaskController extends AbstractController
if (Request::METHOD_POST === $request->getMethod()) {
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
($this->triggerAudit)(AuditTrail::AUDIT_DELETE, $task);
$this->logger->notice('A task has been removed', [
'by_user' => $this->getUser()->getUsername(),
'task_id' => $task->getId(),
@@ -180,6 +185,8 @@ final class SingleTaskController extends AbstractController
$em->flush();
($this->triggerAudit)(AuditTrail::AUDIT_UPDATE, $task);
$this->addFlash('success', $this->translator
->trans('The task has been updated'));
@@ -309,6 +316,12 @@ final class SingleTaskController extends AbstractController
): Response {
$this->denyAccessUnlessGranted(TaskVoter::SHOW, $course);
($this->triggerAudit)(
AuditTrail::AUDIT_LIST,
$course,
description: new \Symfony\Component\Translation\TranslatableMessage('audit.single_task.list_for_course')
);
$filterOrder = $this->buildFilterOrder();
$flags = \array_merge(
$filterOrder->getCheckboxData('status'),
@@ -354,6 +367,8 @@ final class SingleTaskController extends AbstractController
): Response {
$this->denyAccessUnlessGranted(TaskVoter::SHOW, $person);
($this->triggerAudit)(AuditTrail::AUDIT_LIST, $person, description: new \Symfony\Component\Translation\TranslatableMessage('audit.single_task.list_for_person'));
$filterOrder = $this->buildFilterOrder();
$flags = \array_merge(
$filterOrder->getCheckboxData('status'),
@@ -527,6 +542,8 @@ final class SingleTaskController extends AbstractController
$em->flush();
($this->triggerAudit)(AuditTrail::AUDIT_CREATE, $task);
$this->addFlash('success', $this->translator->trans('The task is created'));
if ($request->query->has('returnPath')) {
@@ -569,6 +586,8 @@ final class SingleTaskController extends AbstractController
{
$this->denyAccessUnlessGranted(TaskVoter::SHOW, $task);
($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $task);
if ($task->getContext() instanceof Person) {
$event = new PrivacyEvent($task->getContext(), [
'element_class' => SingleTask::class,