diff --git a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php index fe262318e..141ca049d 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -126,6 +126,7 @@ final class SingleTaskController extends AbstractController } $task->setPerson($person); + $role = TaskVoter::CREATE_PERSON; break; case 'course': $course = $this->getDoctrine()->getManager() @@ -137,15 +138,16 @@ final class SingleTaskController extends AbstractController } $task->setCourse($course); + $role = TaskVoter::CREATE_COURSE; break; default: return new BadRequestHttpException("context with {$entityType} is not supported"); } - $this->denyAccessUnlessGranted(TaskVoter::CREATE, $task, 'You are not ' + $this->denyAccessUnlessGranted($role, $task, 'You are not ' . 'allowed to create this task'); - $form = $this->setCreateForm($task, new Role(TaskVoter::CREATE)); + $form = $this->setCreateForm($task, new Role($role)); $form->handleRequest($request); @@ -266,8 +268,8 @@ final class SingleTaskController extends AbstractController $this->addFlash('success', $this->translator ->trans("The task has been updated")); - if ($person = $task->getContext() instanceof Person) { - $event = new PrivacyEvent($person, array( + if ($task->getContext() instanceof Person) { + $event = new PrivacyEvent($task->getPerson(), array( 'element_class' => SingleTask::class, 'element_id' => $task->getId(), 'action' => 'update' @@ -301,8 +303,8 @@ final class SingleTaskController extends AbstractController return $event->getResponse(); } - if ($person = $task->getContext() instanceof Person) { - $event = new PrivacyEvent($person, array( + if ($task->getContext() instanceof Person) { + $event = new PrivacyEvent($task->getPerson(), array( 'element_class' => SingleTask::class, 'element_id' => $task->getId(), 'action' => 'edit' @@ -511,7 +513,7 @@ final class SingleTaskController extends AbstractController * Arguments: * - user_id * - scope_id - * - course_id + * - s * - person_id * - hide_form (hide the form to filter the tasks) * - status: date state, amongst SingleTaskRepository::DATE_STATUSES, or 'closed' @@ -522,212 +524,44 @@ final class SingleTaskController extends AbstractController * ) */ public function listAction( - PaginatorFactory $paginatorFactory, - SingleTaskRepository $taskRepository, - PersonRepository $personRepository, - AccompanyingPeriodRepository $courseRepository, - CenterRepository $centerRepository, - FormFactoryInterface $formFactory, Request $request ) { - /* @var $viewParams array The parameters for the view */ - /* @var $params array The parameters for the query */ + $this->denyAccessUnlessGranted(TaskVoter::SHOW, null); - $viewParams['person'] = null; - $params['person'] = null; - $viewParams['user'] = null; - $params['user'] = null; - $viewParams['center'] = null; - $params['types'] = null; - $viewParams['accompanyingCourse'] = null; - $params['accompanyingCourse'] = null; + $filterOrder = $this->buildFilterOrder(); + $flags = \array_merge( + $filterOrder->getCheckboxData('status'), + \array_map(fn ($i) => 'state_'.$i, $filterOrder->getCheckboxData('states')) + ); + $nb = $this->singleTaskAclAwareRepository->countByAllViewable( + $filterOrder->getQueryString(), + $flags + ); + $paginator = $this->paginatorFactory->create($nb); - if (!empty($request->query->get('person_id', NULL))) { - - $personId = $request->query->getInt('person_id', 0); - $person = $personRepository->find($personId); - - if ($person === null) { - throw $this->createNotFoundException("This person ' $personId ' does not exist."); - } - $this->denyAccessUnlessGranted(PersonVoter::SEE, $person); - - $viewParams['person'] = $person; - $params['person'] = $person; - } - - if (!empty($request->query->get('course_id', NULL))) { - - $courseId = $request->query->getInt('course_id', 0); - $course = $courseRepository->find($courseId); - - if ($course === null) { - throw $this->createNotFoundException("This accompanying course ' $courseId ' does not exist."); - } - $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $course); - - $viewParams['accompanyingCourse'] = $course; - $params['accompanyingCourse'] = $course; - } - - if (!empty($request->query->get('center_id', NULL))) { - $center = $centerRepository->find($request->query->getInt('center_id')); - if ($center === null) { - throw $this->createNotFoundException('center not found'); - } - $params['center'] = $center; - } - - if(!empty($request->query->get('types', []))) { - $types = $request->query->get('types', []); - if (count($types) > 0) { - $params['types'] = $types; - } - } - - if (!empty($request->query->get('user_id', null))) { - if ($request->query->get('user_id') === '_unassigned') { - $params['unassigned'] = true; - } else { - - $userId = $request->query->getInt('user_id', 0); - $user = $this->getDoctrine()->getManager() - ->getRepository(User::class) - ->find($userId); - - if ($user === null) { - throw $this->createNotFoundException("This user ' $userId ' does not exist."); - } - - $viewParams['user'] = $user; - $params['user'] = $user; - } - } - - if (!empty($request->query->get('scope_id'))) { - - $scopeId = $request->query->getInt('scope_id', 0); - - $scope = $this->getDoctrine()->getManager() - ->getRepository(Scope::class) - ->find($scopeId); - - if ($scope === null) { - throw $this->createNotFoundException("This scope' $scopeId 'does not exist."); - } - - $viewParams['scope'] = $scope; - $params['scope'] = $scope; - } - - $possibleStatuses = \array_merge(SingleTaskRepository::DATE_STATUSES, [ 'closed' ]); - $statuses = $request->query->get('status', $possibleStatuses); - - $diff = \array_diff($statuses, $possibleStatuses); - if (count($diff) > 0) { - return new Response( - 'date_status not allowed: '. \implode(', ', $diff), - Response::HTTP_BAD_REQUEST - ); - } - - $viewParams['isSingleStatus'] = $singleStatus = count($statuses) === 1; - - $tasks_count = 0; - - foreach($statuses as $status) { - if($request->query->has('status') - && FALSE === \in_array($status, $statuses)) { - continue; - } - - if (in_array($status, SingleTaskRepository::DATE_STATUSES)) { - $params['date_status'] = $status; - $params['is_closed'] = false; - } else { - $params['date_status'] = null; - $params['is_closed'] = true; - } - - $count = $taskRepository - ->countByParameters($params, $this->getUser()) - ; - $paginator = $paginatorFactory->create($count); - - $viewParams['single_task_'.$status.'_count'] = $count; - $viewParams['single_task_'.$status.'_paginator'] = $paginator; - $viewParams['single_task_'.$status.'_tasks'] = $taskRepository - ->findByParameters($params, $this->getUser(), - $singleStatus ? $paginator->getCurrentPage()->getFirstItemNumber() : 0, - $singleStatus ? $paginator->getItemsPerPage() : 10) - ; - - $tasks_count = $tasks_count + $count; - } - - $viewParams['tasks_count'] = $tasks_count; - - if ($viewParams['person'] !== null){ - $viewParams['layout'] = '@ChillPerson/Person/layout.html.twig'; - } else if ($viewParams['accompanyingCourse'] !== null){ - $viewParams['layout'] = '@ChillPerson/AccompanyingCourse/layout.html.twig'; + if (0 < $nb) { + $tasks = $this->singleTaskAclAwareRepository->findByAllViewable( + $filterOrder->getQueryString(), + $flags, + $paginator->getCurrentPageFirstItemNumber(), + $paginator->getItemsPerPage(), + [ + 'startDate' => 'DESC', + 'endDate' => 'DESC', + ] + ); } else { - $viewParams['layout'] = '@ChillMain/layout.html.twig'; + $tasks = []; } - $form = $formFactory->createNamed(null, SingleTaskListType::class, null, [ - 'person' => $viewParams['person'], - 'method' => Request::METHOD_GET, - 'csrf_protection' => false, - 'add_type' => true - ]); + return $this->render('@ChillTask/SingleTask/List/index.html.twig', [ + 'tasks' => $tasks, + 'paginator' => $paginator, + 'filter_order' => $filterOrder + ]); - $form->handleRequest($request); - - if (isset($person)) { - $event = new PrivacyEvent($person, array( - 'element_class' => SingleTask::class, - 'action' => 'list' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - } - - return $this->render('@ChillTask/SingleTask/index.html.twig', - array_merge($viewParams, [ 'form' => $form->createView() ])); } - - /* - protected function getPersonParam(EntityManagerInterface $em) - { - $person = $em->getRepository(Person::class) - ->find($request->query->getInt('person_id')) - ; - - if (NULL === $person) { - throw $this->createNotFoundException('person not found'); - } - - $this->denyAccessUnlessGranted(PersonVoter::SEE, $person, "You are " - . "not allowed to see this person"); - - return $person; - } - - protected function getUserParam(EntityManagerInterface $em) - { - $user = $em->getRepository(User::class) - ->find($request->query->getInt('user_id')) - ; - - if (NULL === $user) { - throw $this->createNotFoundException('user not found'); - } - - return $user; - } - */ - /** * Creates a form to delete a Task entity by id. * diff --git a/src/Bundle/ChillTaskBundle/Entity/SingleTask.php b/src/Bundle/ChillTaskBundle/Entity/SingleTask.php index c22f47361..cef59a10a 100644 --- a/src/Bundle/ChillTaskBundle/Entity/SingleTask.php +++ b/src/Bundle/ChillTaskBundle/Entity/SingleTask.php @@ -19,6 +19,10 @@ use Doctrine\Common\Collections\Collection; * @ORM\Index( * name="by_current_state", * columns={ "current_states" } + * ), + * @ORM\Index( + * name="by_end_date", + * columns={ "end_date" } * ) * } * ) diff --git a/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php b/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php index c97ea3549..c728096cb 100644 --- a/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php +++ b/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepository.php @@ -106,6 +106,31 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository ->getQuery()->getSingleScalarResult(); } + public function countByAllViewable( + ?string $pattern = null, + ?array $flags = [] + ): int { + $qb = $this->buildBaseQuery($pattern, $flags); + + return $this + ->addACLGlobal($qb) + ->select('COUNT(t)') + ->getQuery()->getSingleScalarResult(); + } + + public function findByAllViewable( + ?string $pattern = null, + ?array $flags = [], + ?int $start = 0, + ?int $limit = 50, + ?array $orderBy = [] + ): array { + $qb = $this->buildBaseQuery($pattern, $flags); + $qb = $this->addACLGlobal($qb); + + return $this->getResult($qb, $start, $limit, $orderBy); + } + public function buildQueryByCourse( AccompanyingPeriod $course, ?string $pattern = null, @@ -175,6 +200,50 @@ final class SingleTaskAclAwareRepository implements SingleTaskAclAwareRepository ->setParameter('scopes', $scopes); } + private function addACLGlobal( + QueryBuilder $qb + ): QueryBuilder { + $allowedCenters = $this->authorizationHelper + ->getReachableCenters($this->security->getUser(), TaskVoter::SHOW); + + if ([] === $allowedCenters) { + $qb + ->andWhere($qb->expr()->lt('t.id', ':falseid')) + ->setParameter('falseid', -1); + } + + $qb->leftJoin('t.person', 'person') + ->leftJoin('t.course', 'course') + ->leftJoin('course.participations', 'participation') + ->leftJoin('participation.person', 'person_p') + ; + $qb->distinct(true); + + $k = 0; + $orX = $qb->expr()->orX(); + foreach ($allowedCenters as $center) { + $allowedScopes = $this->authorizationHelper->getReachableScopes($this->security->getUser(), + TaskVoter::SHOW, $center); + + $and = $qb->expr()->andX( + $qb->expr()->orX( + $qb->expr()->eq('person.center', ':center_'.$k), + $qb->expr()->eq('person_p.center', ':center_'.$k) + ), + $qb->expr()->in('t.circle', ':scopes_'.$k) + ); + $qb + ->setParameter('center_'.$k, $center) + ->setParameter('scopes_'.$k, $allowedScopes); + $orX->add($and); + + $k++; + } + $qb->andWhere($orX); + + return $qb; + } + public function buildBaseQuery ( ?string $pattern = null, ?array $flags = [] diff --git a/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepositoryInterface.php b/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepositoryInterface.php index 0c6f4fc57..58532daa0 100644 --- a/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepositoryInterface.php +++ b/src/Bundle/ChillTaskBundle/Repository/SingleTaskAclAwareRepositoryInterface.php @@ -40,4 +40,17 @@ interface SingleTaskAclAwareRepositoryInterface ?string $pattern = null, ?array $flags = [] ): int; + + public function countByAllViewable( + ?string $pattern = null, + ?array $flags = [] + ): int; + + public function findByAllViewable( + ?string $pattern = null, + ?array $flags = [], + ?int $start = 0, + ?int $limit = 50, + ?array $orderBy = [] + ): array; }