denyAccessUnlessGranted('ROLE_VIEWER'); $session = $request->getSession(); $profileId = $session->get('profileId'); if (!$profileId) { return $this->json(['message' => 'Aucun profil actif.'], 401); } $profile = $this->profiles->find($profileId); if (!$profile) { return $this->json(['message' => 'Profil introuvable.'], 401); } $payload = json_decode($request->getContent(), true); if (!is_array($payload)) { return $this->json(['message' => 'Payload JSON invalide.'], 400); } $content = trim((string) ($payload['content'] ?? '')); $entityType = trim((string) ($payload['entityType'] ?? '')); $entityId = trim((string) ($payload['entityId'] ?? '')); $entityName = isset($payload['entityName']) ? trim((string) $payload['entityName']) : null; if ('' === $content) { return $this->json(['message' => 'Le contenu est requis.'], 400); } $allowedTypes = ['machine', 'piece', 'composant', 'product', 'piece_category', 'component_category', 'product_category', 'machine_skeleton']; if (!in_array($entityType, $allowedTypes, true)) { return $this->json(['message' => 'Type d\'entité invalide.'], 400); } if ('' === $entityId) { return $this->json(['message' => 'L\'identifiant de l\'entité est requis.'], 400); } $authorName = trim(sprintf('%s %s', $profile->getFirstName(), $profile->getLastName())); if ('' === $authorName) { $authorName = $profile->getEmail() ?? 'Inconnu'; } $comment = new Comment(); $comment->setContent($content); $comment->setEntityType($entityType); $comment->setEntityId($entityId); $comment->setEntityName($entityName); $comment->setAuthorId($profileId); $comment->setAuthorName($authorName); $this->entityManager->persist($comment); $this->entityManager->flush(); return $this->json($this->normalize($comment), 201); } #[Route('/{id}/resolve', name: 'api_comments_resolve', methods: ['PATCH'])] public function resolve(string $id, Request $request): JsonResponse { $this->denyAccessUnlessGranted('ROLE_GESTIONNAIRE'); $comment = $this->entityManager->getRepository(Comment::class)->find($id); if (!$comment) { return $this->json(['message' => 'Commentaire introuvable.'], 404); } $session = $request->getSession(); $profileId = $session->get('profileId'); $profile = $profileId ? $this->profiles->find($profileId) : null; $resolverName = 'Inconnu'; if ($profile) { $resolverName = trim(sprintf('%s %s', $profile->getFirstName(), $profile->getLastName())); if ('' === $resolverName) { $resolverName = $profile->getEmail() ?? 'Inconnu'; } } $comment->setStatus('resolved'); $comment->setResolvedById($profileId); $comment->setResolvedByName($resolverName); $comment->setResolvedAt(new DateTimeImmutable()); $this->entityManager->flush(); return $this->json($this->normalize($comment)); } #[Route('/stats/unresolved-count', name: 'api_comments_unresolved_count', methods: ['GET'])] public function unresolvedCount(): JsonResponse { $this->denyAccessUnlessGranted('ROLE_VIEWER'); $count = $this->entityManager->getRepository(Comment::class) ->count(['status' => 'open']) ; return $this->json(['count' => $count]); } private function normalize(Comment $comment): array { return [ 'id' => $comment->getId(), 'content' => $comment->getContent(), 'entityType' => $comment->getEntityType(), 'entityId' => $comment->getEntityId(), 'entityName' => $comment->getEntityName(), 'authorId' => $comment->getAuthorId(), 'authorName' => $comment->getAuthorName(), 'status' => $comment->getStatus(), 'resolvedById' => $comment->getResolvedById(), 'resolvedByName' => $comment->getResolvedByName(), 'resolvedAt' => $comment->getResolvedAt()?->format(DateTimeInterface::ATOM), 'createdAt' => $comment->getCreatedAt()->format(DateTimeInterface::ATOM), 'updatedAt' => $comment->getUpdatedAt()->format(DateTimeInterface::ATOM), ]; } }