feat : extend export endpoint for multi-user, multi-project, client filters
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -47,27 +47,65 @@ class TimeEntryExportController extends AbstractController
|
||||
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;
|
||||
// --- Users ---
|
||||
$users = null;
|
||||
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
||||
/** @var User $user */
|
||||
$user = $this->security->getUser();
|
||||
/** @var User $currentUser */
|
||||
$currentUser = $this->security->getUser();
|
||||
$users = [$currentUser];
|
||||
} else {
|
||||
$userId = $request->query->getInt('user');
|
||||
if ($userId > 0) {
|
||||
$user = $this->entityManager->getRepository(User::class)->find($userId);
|
||||
/** @var int[] $userIds */
|
||||
$userIds = array_filter(
|
||||
array_map('intval', (array) $request->query->all('users')),
|
||||
fn (int $id) => $id > 0,
|
||||
);
|
||||
if ([] !== $userIds) {
|
||||
$users = $this->entityManager->getRepository(User::class)->findBy(['id' => $userIds]);
|
||||
}
|
||||
}
|
||||
|
||||
$project = null;
|
||||
$projectId = $request->query->getInt('project');
|
||||
if ($projectId > 0) {
|
||||
$project = $this->entityManager->getRepository(Project::class)->find($projectId);
|
||||
// --- Client (filter projects by client) ---
|
||||
$clientId = $request->query->getInt('client');
|
||||
$clientProjects = null;
|
||||
if ($clientId > 0) {
|
||||
$clientProjects = $this->entityManager->getRepository(Project::class)->findBy(['client' => $clientId]);
|
||||
}
|
||||
|
||||
// --- Projects ---
|
||||
$projects = null;
|
||||
|
||||
/** @var int[] $projectIds */
|
||||
$projectIds = array_filter(
|
||||
array_map('intval', (array) $request->query->all('projects')),
|
||||
fn (int $id) => $id > 0,
|
||||
);
|
||||
if ([] !== $projectIds) {
|
||||
$projects = $this->entityManager->getRepository(Project::class)->findBy(['id' => $projectIds]);
|
||||
}
|
||||
|
||||
// Merge: if both client and projects are set, intersect; if only client, use client projects
|
||||
if (null !== $clientProjects && null !== $projects) {
|
||||
$clientProjectIds = array_map(fn (Project $p) => $p->getId(), $clientProjects);
|
||||
$projects = array_values(array_filter($projects, fn (Project $p) => in_array($p->getId(), $clientProjectIds, true)));
|
||||
if ([] === $projects) {
|
||||
$projects = null;
|
||||
// No matching projects — force empty result by using a dummy condition
|
||||
$entries = [];
|
||||
$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;
|
||||
}
|
||||
} elseif (null !== $clientProjects) {
|
||||
$projects = $clientProjects;
|
||||
}
|
||||
|
||||
/** @var int[] $tagIds */
|
||||
@@ -79,8 +117,8 @@ class TimeEntryExportController extends AbstractController
|
||||
$entries = $this->timeEntryRepository->findForExport(
|
||||
$after,
|
||||
$before,
|
||||
$user,
|
||||
$project,
|
||||
$users ?: null,
|
||||
$projects ?: null,
|
||||
$tagIds ?: null,
|
||||
);
|
||||
|
||||
|
||||
@@ -30,15 +30,17 @@ class TimeEntryRepository extends ServiceEntityRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null|int[] $tagIds
|
||||
* @param null|User[] $users
|
||||
* @param null|Project[] $projects
|
||||
* @param null|int[] $tagIds
|
||||
*
|
||||
* @return TimeEntry[]
|
||||
*/
|
||||
public function findForExport(
|
||||
DateTimeImmutable $after,
|
||||
DateTimeImmutable $before,
|
||||
?User $user = null,
|
||||
?Project $project = null,
|
||||
?array $users = null,
|
||||
?array $projects = null,
|
||||
?array $tagIds = null,
|
||||
): array {
|
||||
$qb = $this->createQueryBuilder('te')
|
||||
@@ -49,15 +51,15 @@ class TimeEntryRepository extends ServiceEntityRepository
|
||||
->orderBy('te.startedAt', 'ASC')
|
||||
;
|
||||
|
||||
if (null !== $user) {
|
||||
$qb->andWhere('te.user = :user')
|
||||
->setParameter('user', $user)
|
||||
if (null !== $users && [] !== $users) {
|
||||
$qb->andWhere('te.user IN (:users)')
|
||||
->setParameter('users', $users)
|
||||
;
|
||||
}
|
||||
|
||||
if (null !== $project) {
|
||||
$qb->andWhere('te.project = :project')
|
||||
->setParameter('project', $project)
|
||||
if (null !== $projects && [] !== $projects) {
|
||||
$qb->andWhere('te.project IN (:projects)')
|
||||
->setParameter('projects', $projects)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user