From c7d12f6acd461117aaab405b0df9a545a30e699d Mon Sep 17 00:00:00 2001 From: matthieu Date: Wed, 20 May 2026 00:10:53 +0200 Subject: [PATCH] feat(mail) : MailCreateTaskController - POST /api/mail/messages/{id}/create-task - cree une Task avec titre = subject du mail (max 255 chars) - utilise findMaxNumberByProjectForUpdate pour numero (advisory lock PG) - transaction wrapInTransaction pour eviter race conditions - taskGroupId et priorityId optionnels via body JSON - cree automatiquement le TaskMailLink (mail <-> tache) - retourne 201 + taskId/taskNumber/taskTitle/messageId Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Mail/MailCreateTaskController.php | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/Controller/Mail/MailCreateTaskController.php diff --git a/src/Controller/Mail/MailCreateTaskController.php b/src/Controller/Mail/MailCreateTaskController.php new file mode 100644 index 0000000..651c661 --- /dev/null +++ b/src/Controller/Mail/MailCreateTaskController.php @@ -0,0 +1,105 @@ + '\d+'])] +#[IsGranted('IS_AUTHENTICATED_FULLY')] +class MailCreateTaskController extends AbstractController +{ + public function __construct( + private readonly MailMessageRepository $messageRepository, + private readonly EntityManagerInterface $em, + private readonly MailAccessChecker $accessChecker, + private readonly TaskRepository $taskRepository, + ) {} + + public function __invoke(Request $request, int $id): JsonResponse + { + $this->accessChecker->ensureCanAccessMail($this->getUser()); + + $message = $this->messageRepository->find($id); + if (null === $message) { + throw new NotFoundHttpException('Message not found'); + } + + $body = json_decode($request->getContent(), true); + $projectId = $body['projectId'] ?? null; + + if (null === $projectId) { + throw new UnprocessableEntityHttpException('projectId is required'); + } + + $project = $this->em->getRepository(Project::class)->find($projectId); + if (null === $project) { + throw new NotFoundHttpException('Project not found'); + } + + $title = $message->getSubject() ?? 'Mail sans sujet'; + if (mb_strlen($title) > 255) { + $title = mb_substr($title, 0, 252).'...'; + } + + $result = $this->em->wrapInTransaction(function () use ($project, $title, $body, $message) { + $maxNumber = $this->taskRepository->findMaxNumberByProjectForUpdate($project); + + $task = new Task(); + $task->setProject($project); + $task->setTitle($title); + $task->setNumber($maxNumber + 1); + + if (isset($body['taskGroupId']) && null !== $body['taskGroupId']) { + $taskGroup = $this->em->getRepository(TaskGroup::class)->find($body['taskGroupId']); + if (null !== $taskGroup) { + $task->setGroup($taskGroup); + } + } + + if (isset($body['priorityId']) && null !== $body['priorityId']) { + $priority = $this->em->getRepository(TaskPriority::class)->find($body['priorityId']); + if (null !== $priority) { + $task->setPriority($priority); + } + } + + $this->em->persist($task); + + $link = new TaskMailLink(); + $link->setTask($task); + $link->setMailMessage($message); + $link->setLinkedAt(new DateTimeImmutable()); + $link->setLinkedBy($this->getUser()); + $this->em->persist($link); + + $this->em->flush(); + + return $task; + }); + + return $this->json([ + 'taskId' => $result->getId(), + 'taskNumber' => $result->getNumber(), + 'taskTitle' => $result->getTitle(), + 'messageId' => $message->getId(), + ], 201); + } +}