From a8f7c77758cc736d80feced7597017f2c1591745 Mon Sep 17 00:00:00 2001 From: Matthieu Date: Tue, 24 Mar 2026 16:03:35 +0100 Subject: [PATCH] feat : add TimeEntryExportController with auth, validation, and filters Co-Authored-By: Claude Sonnet 4.6 --- src/Controller/TimeEntryExportController.php | 98 ++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/Controller/TimeEntryExportController.php diff --git a/src/Controller/TimeEntryExportController.php b/src/Controller/TimeEntryExportController.php new file mode 100644 index 0000000..ecc558d --- /dev/null +++ b/src/Controller/TimeEntryExportController.php @@ -0,0 +1,98 @@ +query->getString('after'); + $beforeStr = $request->query->getString('before'); + + if ('' === $afterStr || '' === $beforeStr) { + throw new BadRequestHttpException('Les paramètres "after" et "before" sont obligatoires.'); + } + + try { + $after = new DateTimeImmutable($afterStr); + $before = new DateTimeImmutable($beforeStr); + } catch (Exception) { + throw new BadRequestHttpException('Format de date invalide. Utilisez YYYY-MM-DD.'); + } + + // Max range: 12 months + if ($after->modify('+12 months') < $before) { + throw new BadRequestHttpException('La plage de dates ne peut pas dépasser 12 mois.'); + } + + // Authorization: non-admin users can only export their own data + $user = null; + if (!$this->security->isGranted('ROLE_ADMIN')) { + /** @var User $user */ + $user = $this->security->getUser(); + } else { + $userId = $request->query->getInt('user'); + if ($userId > 0) { + $user = $this->entityManager->getRepository(User::class)->find($userId); + } + } + + $project = null; + $projectId = $request->query->getInt('project'); + if ($projectId > 0) { + $project = $this->entityManager->getRepository(Project::class)->find($projectId); + } + + /** @var int[] $tagIds */ + $tagIds = array_filter( + array_map('intval', (array) $request->query->all('tags')), + fn (int $id) => $id > 0, + ); + + $entries = $this->timeEntryRepository->findForExport( + $after, + $before, + $user, + $project, + $tagIds ?: null, + ); + + $tempFile = $this->exportService->generate($entries, $after, $before); + + $filename = sprintf('export-temps-%s_%s.xlsx', $after->format('Y-m-d'), $before->format('Y-m-d')); + + $response = new BinaryFileResponse($tempFile); + $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename); + $response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + $response->deleteFileAfterSend(true); + + return $response; + } +}