Add "list" action to audit functionality and French translations

- Introduced `AUDIT_LIST` constant in `AuditTrail` entity to support "list" action auditing.
- Updated French translations (`messages.fr.yml`) to include label for "list" action.
This commit is contained in:
2026-02-27 15:57:21 +01:00
parent 72131dc2f8
commit b354ea1ce2
5 changed files with 129 additions and 11 deletions

View File

@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\CalendarBundle\Audit\Converter;
use Chill\CalendarBundle\Entity\Calendar;
use Chill\MainBundle\Audit\Subject;
use Chill\MainBundle\Audit\SubjectBag;
use Chill\MainBundle\Audit\SubjectConverterInterface;
use Chill\MainBundle\Audit\SubjectConverterManagerAwareInterface;
use Chill\MainBundle\Audit\SubjectConverterManagerAwareTrait;
final class CalendarSubjectConverter implements SubjectConverterInterface, SubjectConverterManagerAwareInterface
{
use SubjectConverterManagerAwareTrait;
public function supportsConvert(mixed $subject): bool
{
return $subject instanceof Calendar;
}
public function convert(mixed $subject, bool $includeAssociated = false): SubjectBag
{
\assert($subject instanceof Calendar);
$main = new Subject(
type: 'calendar',
identifiers: ['id' => $subject->getId()],
);
$bag = new SubjectBag($main);
if ($includeAssociated) {
if (null !== $subject->getPerson()) {
$bag->append($this->subjectConverterManager->getSubjectsForEntity($subject->getPerson(), false));
}
if (null !== $subject->getAccompanyingPeriod()) {
$bag->append($this->subjectConverterManager->getSubjectsForEntity($subject->getAccompanyingPeriod(), false));
}
}
return $bag;
}
public static function getDefaultPriority(): int
{
return 0;
}
}

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\CalendarBundle\Audit\Displayer;
use Chill\CalendarBundle\Repository\CalendarRepository;
use Chill\MainBundle\Audit\Subject;
use Chill\MainBundle\Audit\SubjectDisplayerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
final class CalendarDisplayer implements SubjectDisplayerInterface
{
public function __construct(
private readonly TranslatorInterface $translator,
private readonly CalendarRepository $calendarRepository,
) {}
public function supportsDisplay(Subject $subject, array $options = []): bool
{
return 'calendar' === $subject->type;
}
public function display(Subject $subject, string $format = 'html', array $options = []): string
{
$calendar = $this->calendarRepository->find($subject->identifiers['id']);
if (null === $calendar) {
$label = $this->translator->trans('audit.calendar.subject', ['id' => $subject->identifiers['id']], 'messages');
} else {
$label = $this->translator->trans('audit.calendar.subject_with_details', ['id' => $subject->identifiers['id'], 'at' => $calendar->getStartDate()], 'messages');
}
return 'html' === $format ? '<span>'.$label.'</span>' : $label;
}
}

View File

@@ -18,6 +18,8 @@ use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterfa
use Chill\CalendarBundle\Repository\CalendarACLAwareRepositoryInterface;
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepository;
use Chill\MainBundle\Audit\TriggerAuditInterface;
use Chill\MainBundle\Entity\AuditTrail;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Repository\UserRepositoryInterface;
@@ -44,6 +46,7 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Contracts\Translation\TranslatorInterface;
class CalendarController extends AbstractController
@@ -61,6 +64,7 @@ class CalendarController extends AbstractController
private readonly AccompanyingPeriodRepository $accompanyingPeriodRepository,
private readonly UserRepositoryInterface $userRepository,
private readonly TranslatorInterface $translator,
private readonly TriggerAuditInterface $triggerAudit,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
private readonly EntityManagerInterface $em,
) {}
@@ -96,6 +100,8 @@ class CalendarController extends AbstractController
'calendar_id' => $entity->getId(),
]);
($this->triggerAudit)(AuditTrail::AUDIT_DELETE, $entity);
$em->remove($entity);
$em->flush();
@@ -148,6 +154,9 @@ class CalendarController extends AbstractController
$calendar->setStatus($calendar::STATUS_CANCELED);
$calendar->setSmsStatus($calendar::SMS_CANCEL_PENDING);
($this->triggerAudit)(AuditTrail::AUDIT_UPDATE, $calendar, description: new TranslatableMessage('audit.calendar.cancel'));
$this->em->flush();
$this->addFlash('success', $this->translator->trans('chill_calendar.calendar_canceled'));
@@ -204,6 +213,7 @@ class CalendarController extends AbstractController
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
($this->triggerAudit)(AuditTrail::AUDIT_UPDATE, $entity);
$em->flush();
$this->addFlash('success', $this->translator->trans('Success : calendar item updated!'));
@@ -250,6 +260,8 @@ class CalendarController extends AbstractController
{
$this->denyAccessUnlessGranted(CalendarVoter::SEE, $accompanyingPeriod);
($this->triggerAudit)(AuditTrail::AUDIT_LIST, $accompanyingPeriod, description: new TranslatableMessage('audit.calendar.list_by_period'));
$filterOrder = $this->buildListFilterOrder();
['from' => $from, 'to' => $to] = $filterOrder->getDateRangeData('startDate');
@@ -283,6 +295,8 @@ class CalendarController extends AbstractController
{
$this->denyAccessUnlessGranted(CalendarVoter::SEE, $person);
($this->triggerAudit)(AuditTrail::AUDIT_LIST, $person, description: new TranslatableMessage('audit.calendar.list_by_person'));
$filterOrder = $this->buildListFilterOrder();
['from' => $from, 'to' => $to] = $filterOrder->getDateRangeData('startDate');
@@ -381,6 +395,8 @@ class CalendarController extends AbstractController
$em->persist($entity);
$em->flush();
($this->triggerAudit)(AuditTrail::AUDIT_CREATE, $entity);
$this->addFlash('success', $this->translator->trans('Success : calendar item created!'));
if ($form->get('save_and_upload_doc')->isClicked()) {
@@ -453,20 +469,12 @@ class CalendarController extends AbstractController
/** @var Calendar $entity */
$entity = $em->getRepository(Calendar::class)->find($id);
($this->triggerAudit)(AuditTrail::AUDIT_VIEW, $entity);
if (null === $entity) {
throw $this->createNotFoundException('Unable to find Calendar entity.');
}
if (null !== $accompanyingPeriod) {
// @TODO: These properties are declared dynamically.
// It must be removed.
// @See https://wiki.php.net/rfc/deprecate_dynamic_properties
$entity->personsAssociated = $entity->getPersonsAssociated();
$entity->personsNotAssociated = $entity->getPersonsNotAssociated();
}
// $deleteForm = $this->createDeleteForm($id, $accompanyingPeriod);
$personsId = array_map(
static fn (Person $p): int => $p->getId(),
$entity->getPersons()->toArray()
@@ -495,7 +503,6 @@ class CalendarController extends AbstractController
'entity' => $entity,
'user' => $user,
'activityData' => $activityData,
// 'delete_form' => $deleteForm->createView(),
]);
}

View File

@@ -39,5 +39,10 @@ services:
autowire: true
resource: '../../Service/'
Chill\CalendarBundle\Audit\:
autoconfigure: true
autowire: true
resource: '../../Audit/'
Chill\CalendarBundle\Service\ShortMessageForCalendarBuilderInterface:
alias: Chill\CalendarBundle\Service\DefaultShortMessageForCalendarBuider

View File

@@ -1,3 +1,10 @@
audit:
calendar:
cancel: Annulation du rendez-vous
subject: Rendez-vous n°{id}
subject_with_details: Rendez-vous n°{id} le {at, date, medium} - {at, time, medium}
list_by_person: Liste les rendez-vous par usager
list_by_period: Liste les rendez-vous par parcours d''accompagnement
chill_calendar:
There are count ignored calendars by date filter: >-
{nbIgnored, plural,