diff --git a/src/Controller/ActivityLogController.php b/src/Controller/ActivityLogController.php new file mode 100644 index 0000000..10e030e --- /dev/null +++ b/src/Controller/ActivityLogController.php @@ -0,0 +1,87 @@ +query->getInt('page', 1)); + $itemsPerPage = min(100, max(1, $request->query->getInt('itemsPerPage', 30))); + + $filters = []; + if ($entityType = $request->query->get('entityType')) { + $filters['entityType'] = $entityType; + } + if ($action = $request->query->get('action')) { + $filters['action'] = $action; + } + + $result = $this->auditLogs->findAllPaginated($page, $itemsPerPage, $filters); + + $actorIds = array_values(array_unique(array_filter(array_map( + static fn ($log) => $log->getActorProfileId(), + $result['items'], + )))); + + $actorMap = []; + if ([] !== $actorIds) { + $profiles = $this->profiles->findBy(['id' => $actorIds]); + foreach ($profiles as $profile) { + $label = trim(sprintf('%s %s', $profile->getFirstName(), $profile->getLastName())); + if ('' === $label) { + $label = $profile->getEmail() ?? $profile->getId(); + } + $actorMap[$profile->getId()] = $label; + } + } + + $items = array_map( + static function ($log) use ($actorMap) { + $actorId = $log->getActorProfileId(); + $snapshot = $log->getSnapshot(); + + return [ + 'id' => $log->getId(), + 'entityType' => $log->getEntityType(), + 'entityId' => $log->getEntityId(), + 'entityName' => $snapshot['name'] ?? null, + 'entityRef' => $snapshot['reference'] ?? null, + 'action' => $log->getAction(), + 'createdAt' => $log->getCreatedAt()->format(DateTimeInterface::ATOM), + 'actor' => $actorId + ? [ + 'id' => $actorId, + 'label' => $actorMap[$actorId] ?? $actorId, + ] + : null, + 'diff' => $log->getDiff(), + 'snapshot' => $snapshot, + ]; + }, + $result['items'], + ); + + return new JsonResponse([ + 'items' => array_values($items), + 'total' => $result['total'], + 'page' => $page, + 'itemsPerPage' => $itemsPerPage, + ]); + } +} diff --git a/src/EventSubscriber/ComposantAuditSubscriber.php b/src/EventSubscriber/ComposantAuditSubscriber.php index 97cf099..e7a90d7 100644 --- a/src/EventSubscriber/ComposantAuditSubscriber.php +++ b/src/EventSubscriber/ComposantAuditSubscriber.php @@ -293,23 +293,28 @@ final class ComposantAuditSubscriber implements EventSubscriber /** * @param iterable $items * - * @return list + * @return list */ private function normalizeCollection(iterable $items): array { - $ids = []; + $entries = []; + $seen = []; foreach ($items as $item) { if (is_object($item) && method_exists($item, 'getId')) { $id = $item->getId(); - if (null !== $id && '' !== $id) { - $ids[] = (string) $id; + if (null === $id || '' === $id || isset($seen[(string) $id])) { + continue; + } + $seen[(string) $id] = true; + if (method_exists($item, 'getName')) { + $entries[] = ['id' => (string) $id, 'name' => (string) $item->getName()]; + } else { + $entries[] = (string) $id; } } } - sort($ids); - - return array_values(array_unique($ids)); + return $entries; } private function normalizeValue(mixed $value): mixed diff --git a/src/EventSubscriber/PieceAuditSubscriber.php b/src/EventSubscriber/PieceAuditSubscriber.php index 2e2b5b1..c802da3 100644 --- a/src/EventSubscriber/PieceAuditSubscriber.php +++ b/src/EventSubscriber/PieceAuditSubscriber.php @@ -293,23 +293,28 @@ final class PieceAuditSubscriber implements EventSubscriber /** * @param iterable $items * - * @return list + * @return list */ private function normalizeCollection(iterable $items): array { - $ids = []; + $entries = []; + $seen = []; foreach ($items as $item) { if (is_object($item) && method_exists($item, 'getId')) { $id = $item->getId(); - if (null !== $id && '' !== $id) { - $ids[] = (string) $id; + if (null === $id || '' === $id || isset($seen[(string) $id])) { + continue; + } + $seen[(string) $id] = true; + if (method_exists($item, 'getName')) { + $entries[] = ['id' => (string) $id, 'name' => (string) $item->getName()]; + } else { + $entries[] = (string) $id; } } } - sort($ids); - - return array_values(array_unique($ids)); + return $entries; } private function normalizeValue(mixed $value): mixed diff --git a/src/EventSubscriber/ProductAuditSubscriber.php b/src/EventSubscriber/ProductAuditSubscriber.php index 61a7c89..c620d92 100644 --- a/src/EventSubscriber/ProductAuditSubscriber.php +++ b/src/EventSubscriber/ProductAuditSubscriber.php @@ -315,23 +315,28 @@ final class ProductAuditSubscriber implements EventSubscriber /** * @param iterable $items * - * @return list + * @return list */ private function normalizeCollection(iterable $items): array { - $ids = []; + $entries = []; + $seen = []; foreach ($items as $item) { if (is_object($item) && method_exists($item, 'getId')) { $id = $item->getId(); - if (null !== $id && '' !== $id) { - $ids[] = (string) $id; + if (null === $id || '' === $id || isset($seen[(string) $id])) { + continue; + } + $seen[(string) $id] = true; + if (method_exists($item, 'getName')) { + $entries[] = ['id' => (string) $id, 'name' => (string) $item->getName()]; + } else { + $entries[] = (string) $id; } } } - sort($ids); - - return array_values(array_unique($ids)); + return $entries; } private function normalizeValue(mixed $value): mixed diff --git a/src/Repository/AuditLogRepository.php b/src/Repository/AuditLogRepository.php index dfdb101..9c3587a 100644 --- a/src/Repository/AuditLogRepository.php +++ b/src/Repository/AuditLogRepository.php @@ -31,7 +31,46 @@ final class AuditLogRepository extends ServiceEntityRepository ->orderBy('a.createdAt', 'DESC') ->setMaxResults($limit) ->getQuery() - ->getResult(); + ->getResult() + ; + } + + /** + * @param array{entityType?: string, action?: string} $filters + * + * @return array{items: list, total: int} + */ + public function findAllPaginated(int $page = 1, int $itemsPerPage = 30, array $filters = []): array + { + $qb = $this->createQueryBuilder('a') + ->orderBy('a.createdAt', 'DESC') + ; + + if (!empty($filters['entityType'])) { + $qb->andWhere('a.entityType = :entityType') + ->setParameter('entityType', $filters['entityType']) + ; + } + + if (!empty($filters['action'])) { + $qb->andWhere('a.action = :action') + ->setParameter('action', $filters['action']) + ; + } + + $countQb = clone $qb; + $countQb->select('COUNT(a.id)') + ->resetDQLPart('orderBy') + ; + $total = (int) $countQb->getQuery()->getSingleScalarResult(); + + $qb->setFirstResult(($page - 1) * $itemsPerPage) + ->setMaxResults($itemsPerPage) + ; + + return [ + 'items' => $qb->getQuery()->getResult(), + 'total' => $total, + ]; } } -