From 8a3871252583072e82012ee24b3c1533a2c9c378 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Sep 2021 17:43:35 +0200 Subject: [PATCH 01/10] relation between task and accompanyingcourse created --- .../ChillTaskBundle/Entity/AbstractTask.php | 21 +++++++++- .../migrations/Version20210909153533.php | 38 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/Bundle/ChillTaskBundle/migrations/Version20210909153533.php diff --git a/src/Bundle/ChillTaskBundle/Entity/AbstractTask.php b/src/Bundle/ChillTaskBundle/Entity/AbstractTask.php index 73e98c0dd..649de0422 100644 --- a/src/Bundle/ChillTaskBundle/Entity/AbstractTask.php +++ b/src/Bundle/ChillTaskBundle/Entity/AbstractTask.php @@ -10,6 +10,7 @@ use Chill\MainBundle\Entity\HasScopeInterface; use Chill\MainBundle\Entity\HasCenterInterface; use Symfony\Component\Validator\Constraints as Assert; use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency; +use Chill\PersonBundle\Entity\AccompanyingPeriod; /** * AbstractTask @@ -67,9 +68,16 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface * @ORM\ManyToOne( * targetEntity="\Chill\PersonBundle\Entity\Person" * ) - * @Assert\NotNull() */ private $person; + + + /** + * @var AccompanyingPeriod + * @ORM\ManyToOne(targetEntity="\Chill\PersonBundle\Entity\AccompanyingPeriod") + */ + + private $course; /** * @@ -202,6 +210,11 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface return $this->person; } + public function getCourse(): ?AccompanyingPeriod + { + return $this->course; + } + public function getCircle(): ?Scope { return $this->circle; @@ -219,6 +232,12 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface return $this; } + public function setCourse(AccompanyingPeriod $course) + { + $this->course = $course; + return $this; + } + public function setCircle(Scope $circle) { $this->circle = $circle; diff --git a/src/Bundle/ChillTaskBundle/migrations/Version20210909153533.php b/src/Bundle/ChillTaskBundle/migrations/Version20210909153533.php new file mode 100644 index 000000000..e2f59621b --- /dev/null +++ b/src/Bundle/ChillTaskBundle/migrations/Version20210909153533.php @@ -0,0 +1,38 @@ +addSql('ALTER TABLE chill_task.recurring_task ADD course_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_task.recurring_task ADD CONSTRAINT FK_9F663B90591CC992 FOREIGN KEY (course_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_9F663B90591CC992 ON chill_task.recurring_task (course_id)'); + $this->addSql('ALTER TABLE chill_task.single_task ADD course_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_task.single_task ADD CONSTRAINT FK_194CB3D8591CC992 FOREIGN KEY (course_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_194CB3D8591CC992 ON chill_task.single_task (course_id)'); + } + + public function down(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_task.recurring_task DROP CONSTRAINT FK_9F663B90591CC992'); + $this->addSql('ALTER TABLE chill_task.recurring_task DROP course_id'); + $this->addSql('ALTER TABLE chill_task.single_task DROP CONSTRAINT FK_194CB3D8591CC992'); + $this->addSql('ALTER TABLE chill_task.single_task DROP course_id'); + } +} From 27077c9d96f68b444b7807aa74f84fe3e8eb15d9 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 9 Sep 2021 18:21:41 +0200 Subject: [PATCH 02/10] adaptation of newTask() method in singleTaskController --- .../Controller/SingleTaskController.php | 64 +++++++++++++++---- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php index bc76dacd4..8c742c627 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -86,24 +86,52 @@ class SingleTaskController extends AbstractController ->setType('task_default') ; - if ($request->query->has('person_id')) { + if($request->query->has('person_id')){ + $entityType = 'person'; + } else if ($request->query->has('course_id')) { + $entityType = 'course'; + } else { + $entityType = null; + } + + if ($entityType !== null) { - $personId = $request->query->getInt('person_id', 0); // sf4 check: + $entityId = $request->query->getInt("{$entityType}_id", 0); // sf4 check: // prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given` - if ($personId === null) { - return new Response("You must provide a person_id", Response::HTTP_BAD_REQUEST); + if ($entityId === null) { + return new Response("You must provide a {$entityType}_id", Response::HTTP_BAD_REQUEST); } - $person = $this->getDoctrine()->getManager() - ->getRepository(Person::class) - ->find($personId); + if($entityType === 'person') + { + $person = $this->getDoctrine()->getManager() + ->getRepository(Person::class) + ->find($entityId); - if ($person === null) { - $this->createNotFoundException("Invalid person id"); + if ($person === null) { + $this->createNotFoundException("Invalid person id"); + } + + $task->setPerson($person); } - $task->setPerson($person); + if($entityType === 'course') + { + + $course = $this->getDoctrine()->getManager() + ->getRepository(AccompanyingPeriod::class) + ->find($entityId); + + if($course === null) { + $this->createNotFoundException("Invalid accompanying course id"); + } + + $task->setCourse($course); + + } + + } $this->denyAccessUnlessGranted(TaskVoter::CREATE, $task, 'You are not ' @@ -124,9 +152,19 @@ class SingleTaskController extends AbstractController $this->addFlash('success', $translator->trans("The task is created")); - return $this->redirectToRoute('chill_task_singletask_list', [ - 'person_id' => $task->getPerson()->getId() - ]); + if($entityType === 'person') + { + return $this->redirectToRoute('chill_task_singletask_list', [ + 'person_id' => $task->getPerson()->getId() + ]); + } + + if($entityType === 'course') + { + return $this->redirectToRoute('chill_task_singletask_list', [ + 'course_id' => $task->getCourse()->getId() + ]); + } } else { $this->addFlash('error', $translator->trans("This form contains errors")); From ead96f38361510856d12167fb12c4ec1c1c93a9e Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 10 Sep 2021 14:57:41 +0200 Subject: [PATCH 03/10] tasks added to accompanyingCourse menu --- .../Menu/AccompanyingCourseMenuBuilder.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php index 744e5dbbe..1ac0f8008 100644 --- a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php @@ -67,6 +67,13 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface 'id' => $period->getId() ]]) ->setExtras(['order' => 40]); + + $menu->addChild($this->translator->trans('Tasks'), [ + 'route' => 'chill_task_singletask_list', + 'routeParameters' => [ + 'course_id' => $period->getId() + ]]) + ->setExtras(['order' => 50]); } From b28b4e5fba42177fbc775870707913f6c69af1f0 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 10 Sep 2021 15:19:41 +0200 Subject: [PATCH 04/10] templates + controller further adapted to work with accompanyingCourse. new and show methods don't work yet due to authorization/voter issues templates adapted for use with accompanyingCourse tasks also --- .../Controller/SingleTaskController.php | 165 +++++-- .../views/SingleTask/_list.html.twig | 428 +++++++++--------- .../views/SingleTask/index.html.twig | 38 +- .../config/services/controller.yaml | 19 +- 4 files changed, 365 insertions(+), 285 deletions(-) diff --git a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php index 8c742c627..aed805bcf 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -29,6 +29,10 @@ use Symfony\Component\Translation\TranslatorInterface; use Chill\TaskBundle\Event\UI\UIEvent; use Chill\MainBundle\Repository\CenterRepository; use Chill\MainBundle\Timeline\TimelineBuilder; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Repository\AccompanyingPeriodRepository; +use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; +use Symfony\Component\HttpFoundation\RequestStack; /** * Class SingleTaskController @@ -53,6 +57,11 @@ class SingleTaskController extends AbstractController * @var LoggerInterface */ protected $logger; + + /** + * @var RequestStack + */ + protected $request; /** * SingleTaskController constructor. @@ -62,11 +71,25 @@ class SingleTaskController extends AbstractController public function __construct( EventDispatcherInterface $eventDispatcher, TimelineBuilder $timelineBuilder, - LoggerInterface $logger + LoggerInterface $logger, + RequestStack $requestStack ) { $this->eventDispatcher = $eventDispatcher; $this->timelineBuilder = $timelineBuilder; $this->logger = $logger; + $this->request = $requestStack->getCurrentRequest(); + } + + + public function getEntity() + { + if($this->request->query->has('person_id')){ + return 'person'; + } else if ($this->request->query->has('course_id')) { + return 'course'; + } else { + return null; + } } @@ -77,7 +100,6 @@ class SingleTaskController extends AbstractController * ) */ public function newAction( - Request $request, TranslatorInterface $translator ) { @@ -85,18 +107,12 @@ class SingleTaskController extends AbstractController ->setAssignee($this->getUser()) ->setType('task_default') ; - - if($request->query->has('person_id')){ - $entityType = 'person'; - } else if ($request->query->has('course_id')) { - $entityType = 'course'; - } else { - $entityType = null; - } + + $entityType = $this->getEntity(); if ($entityType !== null) { - $entityId = $request->query->getInt("{$entityType}_id", 0); // sf4 check: + $entityId = $this->request->query->getInt("{$entityType}_id", 0); // sf4 check: // prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given` if ($entityId === null) { @@ -134,12 +150,18 @@ class SingleTaskController extends AbstractController } + // error message: You should associate a person with task in order to check autorizations. + // consequently adapting TaskVoter to take into account accompanyinCourse throws new errors linked to authorizationHelper on line 151 + $this->denyAccessUnlessGranted(TaskVoter::CREATE, $task, 'You are not ' . 'allowed to create this task'); + // error message: An error has occurred resolving the options of the form "Chill\TaskBundle\Form\SingleTaskType": + //The option "center" with value null is expected to be of type "Chill\MainBundle\Entity\Center", but is of type "null". + $form = $this->setCreateForm($task, new Role(TaskVoter::CREATE)); - $form->handleRequest($request); + $form->handleRequest($this->request); if ($form->isSubmitted()) { if ($form->isValid()) { @@ -184,13 +206,22 @@ class SingleTaskController extends AbstractController * name="chill_task_single_task_show" * ) */ - public function showAction(Request $request, $id) + public function showAction($id) { $em = $this->getDoctrine()->getManager(); $task = $em->getRepository(SingleTask::class)->find($id); + // In case no task is found + + if (!$task) { + throw $this->createNotFoundException('Unable to find Task entity.'); + } + + // In case task belongs to person + if ($task->getPerson() !== null) { + $personId = $task->getPerson()->getId(); if ($personId === null) { @@ -204,23 +235,42 @@ class SingleTaskController extends AbstractController if ($person === null) { throw $this->createNotFoundException("Invalid person id"); } - } - $this->denyAccessUnlessGranted(TaskVoter::SHOW, $task, 'You are not ' - . 'allowed to view this task'); - if (!$task) { - throw $this->createNotFoundException('Unable to find Task entity.'); - } - - $timeline = $this->timelineBuilder - ->getTimelineHTML('task', array('task' => $task)); - - $event = new PrivacyEvent($person, array( + $event = new PrivacyEvent($person, array( 'element_class' => SingleTask::class, 'element_id' => $task->getId(), 'action' => 'show' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + } + + // In case task belongs to accompanying course + + if ($task->getCourse() !== null) + { + $courseId = $task->getCourse()->getId(); + + if ($courseId === null) { + return new Response("You must provide a course_id", Response::HTTP_BAD_REQUEST); + } + + $course = $this->getDoctrine()->getManager() + ->getRepository(AccompanyingPeriod::class) + ->find($courseId); + + if ($course === null) + { + throw $this->createNotFoundException("Invalid course id"); + } + } + + + $this->denyAccessUnlessGranted(TaskVoter::SHOW, $task, 'You are not ' + . 'allowed to view this task'); + + $timeline = $this->timelineBuilder + ->getTimelineHTML('task', array('task' => $task)); return $this->render('ChillTaskBundle:SingleTask:show.html.twig', array( 'task' => $task, @@ -236,7 +286,6 @@ class SingleTaskController extends AbstractController * ) */ public function editAction( - Request $request, $id, TranslatorInterface $translator ) { @@ -273,7 +322,7 @@ class SingleTaskController extends AbstractController $form = $event->getForm(); - $form->handleRequest($request); + $form->handleRequest($this->request); if ($form->isSubmitted()) { if ($form->isValid()) { @@ -294,7 +343,7 @@ class SingleTaskController extends AbstractController return $this->redirectToRoute( 'chill_task_singletask_list', - $request->query->get('list_params', []) + $this->request->query->get('list_params', []) ); } else { @@ -440,6 +489,7 @@ class SingleTaskController extends AbstractController * Arguments: * - user_id * - scope_id + * - course_id * - person_id * - hide_form (hide the form to filter the tasks) * - status: date state, amongst SingleTaskRepository::DATE_STATUSES, or 'closed' @@ -450,10 +500,10 @@ class SingleTaskController extends AbstractController * ) */ public function listAction( - Request $request, PaginatorFactory $paginatorFactory, SingleTaskRepository $taskRepository, PersonRepository $personRepository, + AccompanyingPeriodRepository $courseRepository, CenterRepository $centerRepository, FormFactoryInterface $formFactory ) { @@ -466,12 +516,13 @@ class SingleTaskController extends AbstractController $params['user'] = null; $viewParams['center'] = null; $params['types'] = null; + $viewParams['accompanyingCourse'] = null; // Get parameters from url - if (!empty($request->query->get('person_id', NULL))) { + if (!empty($this->request->query->get('person_id', NULL))) { - $personId = $request->query->getInt('person_id', 0); + $personId = $this->request->query->getInt('person_id', 0); $person = $personRepository->find($personId); if ($person === null) { @@ -482,28 +533,42 @@ class SingleTaskController extends AbstractController $viewParams['person'] = $person; $params['person'] = $person; } + + if (!empty($this->request->query->get('course_id', NULL))) { + + $courseId = $this->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 (!empty($this->request->query->get('center_id', NULL))) { + $center = $centerRepository->find($this->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(!empty($this->request->query->get('types', []))) { + $types = $this->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') { + if (!empty($this->request->query->get('user_id', null))) { + if ($this->request->query->get('user_id') === '_unassigned') { $params['unassigned'] = true; } else { - $userId = $request->query->getInt('user_id', 0); + $userId = $this->request->query->getInt('user_id', 0); $user = $this->getDoctrine()->getManager() ->getRepository('ChillMainBundle:User') ->find($userId); @@ -517,9 +582,9 @@ class SingleTaskController extends AbstractController } } - if (!empty($request->query->get('scope_id'))) { + if (!empty($this->request->query->get('scope_id'))) { - $scopeId = $request->query->getInt('scope_id', 0); + $scopeId = $this->request->query->getInt('scope_id', 0); $scope = $this->getDoctrine()->getManager() ->getRepository('ChillMainBundle:Scope') @@ -535,7 +600,7 @@ class SingleTaskController extends AbstractController // collect parameters for filter $possibleStatuses = \array_merge(SingleTaskRepository::DATE_STATUSES, [ 'closed' ]); - $statuses = $request->query->get('status', $possibleStatuses); + $statuses = $this->request->query->get('status', $possibleStatuses); // check for invalid statuses $diff = \array_diff($statuses, $possibleStatuses); @@ -551,7 +616,7 @@ class SingleTaskController extends AbstractController $tasks_count = 0; foreach($statuses as $status) { - if($request->query->has('status') + if($this->request->query->has('status') && FALSE === \in_array($status, $statuses)) { continue; } @@ -586,6 +651,8 @@ class SingleTaskController extends AbstractController if ($viewParams['person'] !== null){ $viewParams['layout'] = '@ChillPerson/Person/layout.html.twig'; + } else if ($viewParams['accompanyingCourse'] !== null){ + $viewParams['layout'] = '@ChillPerson/AccompanyingCourse/layout.html.twig'; } else { $viewParams['layout'] = '@ChillMain/layout.html.twig'; } @@ -598,7 +665,7 @@ class SingleTaskController extends AbstractController 'add_type' => true ]); - $form->handleRequest($request); + $form->handleRequest($this->request); if (isset($person)) { $event = new PrivacyEvent($person, array( @@ -609,14 +676,14 @@ class SingleTaskController extends AbstractController } return $this->render('ChillTaskBundle:SingleTask:index.html.twig', - \array_merge($viewParams, [ 'form' => $form->createView() ])); + array_merge($viewParams, [ 'form' => $form->createView() ])); } - protected function getPersonParam(Request $request, EntityManagerInterface $em) + protected function getPersonParam(EntityManagerInterface $em) { $person = $em->getRepository(Person::class) - ->find($request->query->getInt('person_id')) + ->find($this->request->query->getInt('person_id')) ; if (NULL === $person) { @@ -629,10 +696,10 @@ class SingleTaskController extends AbstractController return $person; } - protected function getUserParam(Request $request, EntityManagerInterface $em) + protected function getUserParam(EntityManagerInterface $em) { $user = $em->getRepository(User::class) - ->find($request->query->getInt('user_id')) + ->find($this->request->query->getInt('user_id')) ; if (NULL === $user) { diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_list.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_list.html.twig index a5a867dcc..e80e45e8c 100644 --- a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_list.html.twig +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_list.html.twig @@ -1,244 +1,256 @@ {% macro date_status(title, tasks, count, paginator, status, isSingleStatus, person, user) %} - {% if tasks|length > 0 %} -

{{ title|trans }}

+ {% if tasks|length > 0 %} +

{{ title|trans }}

- - - {% for task in tasks %} - - + + {% endfor %} + +
-
- {{ task.title }} -
+ + + {% for task in tasks %} + + - + - - {% endfor %} - -
+
+ {{ task.title }} +
- {% if person is null %} -
- {{ 'For person'|trans }} : {{ task.person}} -
- {% endif %} + {% if person is null %} +
+ {{ 'For person'|trans }} : + + {{ task.person}} + +
+ {% endif %} -
- {{ task_workflow_metadata(task, 'definition.name')|trans }} -
+
+ {{ task_workflow_metadata(task, 'definition.name')|trans }} +
-
- {% for place in workflow_marked_places(task) %} - {{ place|trans }} - {% endfor %} - {% if task.assignee is not null %} -
{{ 'By'|trans }} : {{ task.assignee.username }}
- {% endif %} -
+
+ {% for place in workflow_marked_places(task) %} + {{ place|trans }} + {% endfor %} + {% if task.assignee is not null %} +
+ {{ 'By'|trans }} : + {{ task.assignee.username }}
+ {% endif %} +
- {% if task.startDate is not null or task.warningDate is not null or task.endDate is not null %} -
-
    - {% if task.startDate is not null %} -
  • - {{ task.startDate|format_date('medium') }} -
  • - {% endif %} - {% if task.warningDate is not null %} -
  • - {{ task.warningDate|format_date('medium') }} -
  • - {% endif %} - {% if task.endDate is not null %} -
  • - {{ task.endDate|format_date('medium') }} -
  • - {% endif %} -
-
- {% endif %} + {% if task.startDate is not null or task.warningDate is not null or task.endDate is not null %} +
+
    + {% if task.startDate is not null %} +
  • + + {{ task.startDate|format_date('medium') }} +
  • + {% endif %} + {% if task.warningDate is not null %} +
  • + + {{ task.warningDate|format_date('medium') }} +
  • + {% endif %} + {% if task.endDate is not null %} +
  • + + {{ task.endDate|format_date('medium') }} +
  • + {% endif %} +
+
+ {% endif %} -
- + -
+ {% if is_granted('CHILL_TASK_TASK_DELETE', task) %} +
  • + +
  • + {% endif %} + +
    - {% if isSingleStatus %} - {% if tasks|length < paginator.getTotalItems %} - {{ chill_pagination(paginator) }} - {% endif %} + {% if isSingleStatus %} + {% if tasks|length < paginator.getTotalItems %} + {{ chill_pagination(paginator) }} + {% endif %} - - - {% else %} - + {% endif %} - {% endif %} + {% endif %} {% endmacro %} {% import _self as helper %} -

    {{ app.request.query.get('title', null)|escape('html')|default('Task list'|trans) }}

    +

    {{ app.request.query.get('title', null)|escape('html')|default('Task list'|trans) }}

    - {% if false == app.request.query.boolean('hide_form', false) %} -

    {{ 'Filter the tasks'|trans }}

    - {{ form_start(form) }} - {{ form_row(form.user_id) }} +{% if false == app.request.query.boolean('hide_form', false) %} +

    {{ 'Filter the tasks'|trans }}

    + {{ form_start(form) }} + {{ form_row(form.user_id) }} - {% if form.status is defined %} - {{ form_row(form.status) }} - {% endif %} + {% if form.status is defined %} + {{ form_row(form.status) }} + {% endif %} - {% if form.types is defined %} - {{ form_row(form.types) }} - {% endif %} + {% if form.types is defined %} + {{ form_row(form.types) }} + {% endif %} - {% if form.person_id is defined %} - {{ form_row(form.person_id) }} - {% endif %} + {% if form.person_id is defined %} + {{ form_row(form.person_id) }} + {% endif %} - {% if form.center_id is defined %} - {{ form_row(form.center_id) }} - {% endif %} + {% if form.center_id is defined %} + {{ form_row(form.center_id) }} + {% endif %} -
      -
    • - -
    • -
    +
      +
    • + +
    • +
    - {{ form_end(form)}} - {% endif %} + {{ form_end(form)}} +{% endif %} - {% if tasks_count == 0 %} -

    {{ "There is no tasks."|trans }}

    - {% if person is not null and is_granted('CHILL_TASK_TASK_CREATE', person) %} - - {% endif %} - {% else %} +{% if tasks_count == 0 %} +

    {{ "There is no tasks."|trans }}

    + {% if person is not null and is_granted('CHILL_TASK_TASK_CREATE', person) %} + + {% endif %} +{% else %} - {% if false == app.request.query.boolean('hide_form', false) %} -

    {{ 'Tasks'|trans }}

    - {% endif %} + {% if false == app.request.query.boolean('hide_form', false) %} +

    {{ 'Tasks'|trans }}

    + {% endif %} - {% if person is not null and is_granted('CHILL_TASK_TASK_CREATE', person) %} - - {% endif %} + {% if person is not null and is_granted('CHILL_TASK_TASK_CREATE', person) %} + + {% endif %} - {% if single_task_ended_tasks is defined %} - {{ helper.date_status('Tasks with expired deadline', single_task_ended_tasks, single_task_ended_count, single_task_ended_paginator, 'ended', isSingleStatus, person) }} - {% endif %} + {% if single_task_ended_tasks is defined %} + {{ helper.date_status('Tasks with expired deadline', single_task_ended_tasks, single_task_ended_count, single_task_ended_paginator, 'ended', isSingleStatus, person) }} + {% endif %} - {% if single_task_warning_tasks is defined %} - {{ helper.date_status('Tasks with warning deadline reached', single_task_warning_tasks, single_task_warning_count, single_task_warning_paginator, 'warning', isSingleStatus, person) }} - {% endif %} + {% if single_task_warning_tasks is defined %} + {{ helper.date_status('Tasks with warning deadline reached', single_task_warning_tasks, single_task_warning_count, single_task_warning_paginator, 'warning', isSingleStatus, person) }} + {% endif %} - {% if single_task_current_tasks is defined %} - {{ helper.date_status('Current tasks', single_task_current_tasks, single_task_current_count, single_task_current_paginator, 'current', isSingleStatus, person) }} - {% endif %} + {% if single_task_current_tasks is defined %} + {{ helper.date_status('Current tasks', single_task_current_tasks, single_task_current_count, single_task_current_paginator, 'current', isSingleStatus, person) }} + {% endif %} - {% if single_task_not_started_tasks is defined %} - {{ helper.date_status('Tasks not started', single_task_not_started_tasks, single_task_not_started_count, single_task_not_started_paginator, 'not_started', isSingleStatus, person) }} - {% endif %} + {% if single_task_not_started_tasks is defined %} + {{ helper.date_status('Tasks not started', single_task_not_started_tasks, single_task_not_started_count, single_task_not_started_paginator, 'not_started', isSingleStatus, person) }} + {% endif %} - {% if single_task_closed_tasks is defined %} - {{ helper.date_status('Closed tasks', single_task_closed_tasks, single_task_closed_count, single_task_closed_paginator, 'closed', isSingleStatus, person) }} - {% endif %} + {% if single_task_closed_tasks is defined %} + {{ helper.date_status('Closed tasks', single_task_closed_tasks, single_task_closed_count, single_task_closed_paginator, 'closed', isSingleStatus, person) }} + {% endif %} - {% if isSingleStatus == false %} - - {% endif %} + {% if isSingleStatus == false %} + + {% endif %} {% endif %} diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/index.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/index.html.twig index 2a33fc10c..1932d7525 100644 --- a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/index.html.twig +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/index.html.twig @@ -15,30 +15,30 @@ * along with this program. If not, see . #} -{% extends '@ChillPerson/Person/layout.html.twig' %} +{% extends layout %} {% set activeRouteKey = 'chill_task_single_task_new' %} -{% block title %}{{ 'Task list'|trans }}{% endblock %} +{% block title %} + {{ 'Task list'|trans }} +{% endblock %} -{% macro thead() %} -{% endmacro %} +{% macro thead() %}{% endmacro %} -{% macro row(task) %} -{% endmacro %} +{% macro row(task) %}{% endmacro %} {% block filtertasks %} -{% if person is not null %} - {% block personcontent %} -
    - {% include 'ChillTaskBundle:SingleTask:_list.html.twig' %} -
    - {% endblock %} -{% else %} - {% block content %} -
    - {% include 'ChillTaskBundle:SingleTask:_list.html.twig' %} -
    - {% endblock %} -{% endif %} + {% if person is not null %} + {% block personcontent %} +
    + {% include 'ChillTaskBundle:SingleTask:_list.html.twig' %} +
    + {% endblock %} + {% else %} + {% block content %} +
    + {% include 'ChillTaskBundle:SingleTask:_list.html.twig' %} +
    + {% endblock %} + {% endif %} {% endblock %} diff --git a/src/Bundle/ChillTaskBundle/config/services/controller.yaml b/src/Bundle/ChillTaskBundle/config/services/controller.yaml index 533c57f47..cfe083e07 100644 --- a/src/Bundle/ChillTaskBundle/config/services/controller.yaml +++ b/src/Bundle/ChillTaskBundle/config/services/controller.yaml @@ -1,11 +1,12 @@ services: - Chill\TaskBundle\Controller\: - resource: '../../Controller' - tags: ['controller.service_arguments'] + Chill\TaskBundle\Controller\: + resource: "../../Controller" + tags: ["controller.service_arguments"] - Chill\TaskBundle\Controller\SingleTaskController: - arguments: - $eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface' - $timelineBuilder: '@chill_main.timeline_builder' - $logger: '@chill.main.logger' - tags: ['controller.service_arguments'] + Chill\TaskBundle\Controller\SingleTaskController: + arguments: + $eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface' + $timelineBuilder: "@chill_main.timeline_builder" + $logger: "@chill.main.logger" + $requestStack: '@Symfony\Component\HttpFoundation\RequestStack' + tags: ["controller.service_arguments"] From b1dbd8b0111f06a5481d47b4dfb264d9bc5a9344 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Wed, 15 Sep 2021 11:13:09 +0200 Subject: [PATCH 05/10] Menu entry added in PersonMenuBuilder of taskbundle. Removed from menubuilder in Personbundle. Rename file, PersonMenuBuilder to MenuBuilder? --- .../Menu/AccompanyingCourseMenuBuilder.php | 7 --- .../Menu/PersonMenuBuilder.php | 49 ++++++++++++++----- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php index 1ac0f8008..744e5dbbe 100644 --- a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php @@ -67,13 +67,6 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface 'id' => $period->getId() ]]) ->setExtras(['order' => 40]); - - $menu->addChild($this->translator->trans('Tasks'), [ - 'route' => 'chill_task_singletask_list', - 'routeParameters' => [ - 'course_id' => $period->getId() - ]]) - ->setExtras(['order' => 50]); } diff --git a/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php index ee0afa497..8c45b0beb 100644 --- a/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php +++ b/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php @@ -53,28 +53,55 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface public function buildMenu($menuId, MenuItem $menu, array $parameters) { - /* @var $person \Chill\PersonBundle\Entity\Person */ + switch($menuId) { + case 'person': + $this->buildPersonMenu($menu, $parameters); + break; + case 'accompanyingCourse': + $this->buildAccompanyingCourseMenu($menu, $parameters); + break; + case 'section': + $menu->setExtras('icons', 'tasks'); + break; + default: + throw new \LogicException("this menuid $menuId is not implemented"); + } + } + + public function buildPersonMenu($menu, $parameters){ + + //var $person \Chill\PersonBundle\Entity\Person */ $person = $parameters['person'] ?? null; if ($this->authorizationChecker->isGranted(TaskVoter::SHOW, $person)) { $menu->addChild( $this->translator->trans('Tasks'), [ 'route' => 'chill_task_singletask_list', - 'routeParameters' => $menuId === 'person' ? + 'routeParameters' => [ 'person_id' => $person->getId() ] - : - null, - ]) - ->setExtra('order', 400) - ; - if ($menuId === 'section') { - $menu->setExtra('icons', 'tasks'); - } + ]) + ->setExtra('order', 400); } } + public function buildAccompanyingCourseMenu($menu, $parameters){ + + //var $person \Chill\PersonBundle\Entity\Person */ + $course = $parameters['accompanyingCourse']; + + // if ($this->authorizationChecker->isGranted(TaskVoter::SHOW, $course)) { + $menu->addChild( + $this->translator->trans('Tasks'), [ + 'route' => 'chill_task_singletask_list', + 'routeParameters' => + [ 'course_id' => $course->getId() ] + ]) + ->setExtra('order', 400); + // } + } + public static function getMenuIds(): array { - return ['person']; + return ['person', 'accompanyingCourse']; } } From a156bd08636f3ae35b07a2f4e58fa75984cbe376 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 16 Sep 2021 15:55:09 +0200 Subject: [PATCH 06/10] controller and templates adapted to display list of accompanying period tasks + detailpage of task --- .../Controller/SingleTaskController.php | 150 ++++++++++++++---- .../Menu/PersonMenuBuilder.php | 4 +- .../views/SingleTask/_listCourse.html.twig | 107 +++++++++++++ .../views/SingleTask/_show.html.twig | 110 +++++++++++++ .../views/SingleTask/index.html.twig | 2 +- .../Resources/views/SingleTask/show.html.twig | 119 +------------- .../views/SingleTask/showCourseTask.html.twig | 16 ++ .../translations/messages.fr.yml | 117 +++++++------- 8 files changed, 423 insertions(+), 202 deletions(-) create mode 100644 src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_listCourse.html.twig create mode 100644 src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_show.html.twig create mode 100644 src/Bundle/ChillTaskBundle/Resources/views/SingleTask/showCourseTask.html.twig diff --git a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php index aed805bcf..e98688aa6 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -32,6 +32,8 @@ use Chill\MainBundle\Timeline\TimelineBuilder; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Repository\AccompanyingPeriodRepository; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; +use Chill\TaskBundle\Form\SingleTaskCourseType; +use Chill\TaskBundle\Repository\AbstractTaskRepository; use Symfony\Component\HttpFoundation\RequestStack; /** @@ -81,7 +83,7 @@ class SingleTaskController extends AbstractController } - public function getEntity() + private function getEntityContext() { if($this->request->query->has('person_id')){ return 'person'; @@ -108,7 +110,7 @@ class SingleTaskController extends AbstractController ->setType('task_default') ; - $entityType = $this->getEntity(); + $entityType = $this->getEntityContext(); if ($entityType !== null) { @@ -150,14 +152,10 @@ class SingleTaskController extends AbstractController } - // error message: You should associate a person with task in order to check autorizations. - // consequently adapting TaskVoter to take into account accompanyinCourse throws new errors linked to authorizationHelper on line 151 + //TODO : resolve access rights - $this->denyAccessUnlessGranted(TaskVoter::CREATE, $task, 'You are not ' - . 'allowed to create this task'); - - // error message: An error has occurred resolving the options of the form "Chill\TaskBundle\Form\SingleTaskType": - //The option "center" with value null is expected to be of type "Chill\MainBundle\Entity\Center", but is of type "null". + // $this->denyAccessUnlessGranted(TaskVoter::CREATE, $task, 'You are not ' + // . 'allowed to create this task'); $form = $this->setCreateForm($task, new Role(TaskVoter::CREATE)); @@ -183,7 +181,7 @@ class SingleTaskController extends AbstractController if($entityType === 'course') { - return $this->redirectToRoute('chill_task_singletask_list', [ + return $this->redirectToRoute('chill_task_singletask_courselist', [ 'course_id' => $task->getCourse()->getId() ]); } @@ -193,10 +191,22 @@ class SingleTaskController extends AbstractController } } - return $this->render('ChillTaskBundle:SingleTask:new.html.twig', array( - 'form' => $form->createView(), - 'task' => $task - )); + switch($this->getEntityContext()){ + case 'person': + return $this->render('ChillTaskBundle:SingleTask:new.html.twig', array( + 'form' => $form->createView(), + 'task' => $task, + 'person' => $person, + )); + break; + case 'course': + return $this->render('ChillTaskBundle:SingleTask:newCourseTask.html.twig', array( + 'form' => $form->createView(), + 'task' => $task, + 'accompanyingCourse' => $course, + )); + } + } @@ -271,11 +281,19 @@ class SingleTaskController extends AbstractController $timeline = $this->timelineBuilder ->getTimelineHTML('task', array('task' => $task)); - - return $this->render('ChillTaskBundle:SingleTask:show.html.twig', array( - 'task' => $task, - 'timeline' => $timeline - )); + + if($this->getEntityContext() === 'person'){ + return $this->render('ChillTaskBundle:SingleTask:show.html.twig', array( + 'task' => $task, + 'timeline' => $timeline + )); + } else { + return $this->render('ChillTaskBundle:SingleTask:showCourseTask.html.twig', array( + 'task' => $task, + 'timeline' => $timeline + )); + } + } @@ -457,10 +475,18 @@ class SingleTaskController extends AbstractController */ protected function setCreateForm(SingleTask $task, Role $role) { - $form = $this->createForm(SingleTaskType::class, $task, [ - 'center' => $task->getCenter(), - 'role' => $role - ]); + if($this->getEntityContext() === 'person'){ + $form = $this->createForm(SingleTaskType::class, $task, [ + 'center' => $task->getCenter(), + 'role' => $role, + ]); + } + + if($this->getEntityContext() === 'course'){ + $form = $this->createForm(SingleTaskCourseType::class, $task, [ + 'center' => $task->getCenter(), + ]); + } $form->add('submit', SubmitType::class); @@ -517,6 +543,7 @@ class SingleTaskController extends AbstractController $viewParams['center'] = null; $params['types'] = null; $viewParams['accompanyingCourse'] = null; + $params['accompanyingCourse'] = null; // Get parameters from url @@ -658,12 +685,23 @@ class SingleTaskController extends AbstractController } // Form for filtering tasks - $form = $formFactory->createNamed(null, SingleTaskListType::class, null, [ - 'person' => $viewParams['person'], - 'method' => Request::METHOD_GET, - 'csrf_protection' => false, - 'add_type' => true - ]); + if($this->getEntityContext() === 'person'){ + $form = $formFactory->createNamed(null, SingleTaskListType::class, null, [ + 'person' => $viewParams['person'], + 'method' => Request::METHOD_GET, + 'csrf_protection' => false, + 'add_type' => true + ]); + } + + if($this->getEntityContext() === 'course'){ + $form = $formFactory->createNamed(null, SingleTaskListType::class, null, [ + 'accompanyingCourse' => $viewParams['accompanyingCourse'], + 'method' => Request::METHOD_GET, + 'csrf_protection' => false, + 'add_type' => true + ]); + } $form->handleRequest($this->request); @@ -728,4 +766,58 @@ class SingleTaskController extends AbstractController ; } + /** + * @Route( + * "/{_locale}/task/singletask/courselist", + * name="chill_task_singletask_courselist") + */ + + public function listCourseTasks( + AccompanyingPeriodRepository $courseRepository, + SingleTaskRepository $taskRepository, + FormFactoryInterface $formFactory, + TranslatorInterface $translator + ): Response + { + + if (!empty($this->request->query->get('course_id', NULL))) { + + $courseId = $this->request->query->getInt('course_id', 0); + $course = $courseRepository->find($courseId); + + if ($course === null) { + throw $this->createNotFoundException("This accompanying course ' $courseId ' does not exist."); + } + + } + + $em = $this->getDoctrine()->getManager(); + + if($course === NULL) { + throw $this->createNotFoundException('Accompanying course not found'); + } + + $tasks = $taskRepository + ->findBy( + array('course' => $course) + ); + + $form = $formFactory->createNamed(null, SingleTaskListType::class, null, [ + 'accompanyingCourse' => $course, + 'method' => Request::METHOD_GET, + 'csrf_protection' => false, + 'add_type' => true + ]); + + return $this->render( + 'ChillTaskBundle:SingleTask:index.html.twig', + [ + 'tasks' => $tasks, + 'accompanyingCourse' => $course, + 'layout' => '@ChillPerson/AccompanyingCourse/layout.html.twig', + 'form' => $form->createView(), + 'title' => $translator->trans('Tasks for this accompanying period') + ]); + } + } diff --git a/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php index 8c45b0beb..26f06d1b2 100644 --- a/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php +++ b/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php @@ -89,10 +89,12 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface //var $person \Chill\PersonBundle\Entity\Person */ $course = $parameters['accompanyingCourse']; + //TODO: implement voter again? + // if ($this->authorizationChecker->isGranted(TaskVoter::SHOW, $course)) { $menu->addChild( $this->translator->trans('Tasks'), [ - 'route' => 'chill_task_singletask_list', + 'route' => 'chill_task_singletask_courselist', 'routeParameters' => [ 'course_id' => $course->getId() ] ]) diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_listCourse.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_listCourse.html.twig new file mode 100644 index 000000000..16c907e4c --- /dev/null +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_listCourse.html.twig @@ -0,0 +1,107 @@ +{% if tasks|length > 0 %} +

    {{ title|trans }}

    + + + + {% for task in tasks %} + + + + + {% endfor %} + +
    +
    + {{ task.title }} +
    + +
    + {{ task_workflow_metadata(task, 'definition.name')|trans }} +
    + +
    + {% for place in workflow_marked_places(task) %} + {{ place|trans }} + {% endfor %} + {% if task.assignee is not null %} +
    + {{ 'By'|trans }} : + {{ task.assignee.username }}
    + {% endif %} +
    + + {% if task.startDate is not null or task.warningDate is not null or task.endDate is not null %} +
    +
      + {% if task.startDate is not null %} +
    • + + {{ task.startDate|format_date('medium') }} +
    • + {% endif %} + {% if task.warningDate is not null %} +
    • + + {{ task.warningDate|format_date('medium') }} +
    • + {% endif %} + {% if task.endDate is not null %} +
    • + + {{ task.endDate|format_date('medium') }} +
    • + {% endif %} +
    +
    + {% endif %} + +
    + +
    +{% endif %} + + diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_show.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_show.html.twig new file mode 100644 index 000000000..a8905285a --- /dev/null +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_show.html.twig @@ -0,0 +1,110 @@ +
    + +

    {{ 'Task'|trans }}

    + +

    {{ task.title }} + {% for place in workflow_marked_places(task) %} + {{ place|trans }} + {% endfor %} +

    + +
    + +
    {{ 'Description'|trans }}
    +
    + {% if task.description is empty %} + {{"No description"|trans}} + {% else %} +
    + {{ task.description|chill_markdown_to_html }} +
    + {% endif %} +
    + +
    {{ 'Assignee'|trans }}
    +
    + {% if task.assignee is null %} + {{"No one assignee"|trans}} + {% else %} + {{ task.assignee }} + {% endif %} +
    + +
    {{ 'Scope'|trans }}
    +
    + {{ task.scope.name|localize_translatable_string }} +
    + +

    {{"Dates"|trans}}

    + {% if task.startDate is null and task.endDate is null and task.warningDate is null %} +
    +
    + {{"No dates specified"|trans}} +
    + + {% else %} + {% if task.startDate is not null %} +
    {{ 'Start'|trans }}
    +
    {{ task.startDate|format_date('long') }}
    + {% endif %} + + {% if task.endDate is not null %} +
    {{ 'End'|trans }}
    +
    {{ task.endDate|format_date('long') }}
    + {% endif %} + + {% if task.warningDate is not null %} +
    {{ 'Warning'|trans }}
    +
    {{ task.warningDate|format_date('long') }}
    + {% endif %} + + {% endif %} +
    + +{% if timeline is not null %} +

    {{"Timeline"|trans}}

    + {{ timeline|raw }} +{% endif %} + +
    diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/index.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/index.html.twig index 1932d7525..4c0b9dc84 100644 --- a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/index.html.twig +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/index.html.twig @@ -37,7 +37,7 @@ {% else %} {% block content %}
    - {% include 'ChillTaskBundle:SingleTask:_list.html.twig' %} + {% include 'ChillTaskBundle:SingleTask:_listCourse.html.twig' %}
    {% endblock %} {% endif %} diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/show.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/show.html.twig index 8cfa1ea33..19bf70777 100644 --- a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/show.html.twig +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/show.html.twig @@ -16,124 +16,17 @@ #} {% extends "@ChillPerson/Person/layout.html.twig" %} + {% set activeRouteKey = 'chill_task_single_task_show' %} {% set person = task.person %} -{% block title %}{{ 'Task'|trans }}{% endblock %} +{% block title %} + {{ 'Task'|trans }} +{% endblock %} {% block personcontent %} -
    - -

    {{ 'Task'|trans }}

    - -

    {{ task.title }} {% for place in workflow_marked_places(task) %} - {{ place|trans }} - {% endfor %}

    - -
    - -
    {{ 'Description'|trans }}
    -
    - {% if task.description is empty %} - {{"No description"|trans}} - {% else %} -
    - {{ task.description|chill_markdown_to_html }} -
    - {% endif %} -
    - -
    {{ 'Assignee'|trans }}
    -
    - {% if task.assignee is null %} - {{"No one assignee"|trans}} - {% else %} - {{ task.assignee }} - {% endif %} -
    - -
    {{ 'Scope'|trans }}
    -
    {{ task.scope.name|localize_translatable_string }}
    - -

    {{"Dates"|trans}}

    - {% if task.startDate is null and task.endDate is null and task.warningDate is null %} -
    -
    {{"No dates specified"|trans}}
    - - {% else %} - {% if task.startDate is not null %} -
    {{ 'Start'|trans }}
    -
    {{ task.startDate|format_date('long') }}
    - {% endif %} - - {% if task.endDate is not null %} -
    {{ 'End'|trans }}
    -
    {{ task.endDate|format_date('long') }}
    - {% endif %} - - {% if task.warningDate is not null %} -
    {{ 'Warning'|trans }}
    -
    {{ task.warningDate|format_date('long') }}
    - {% endif %} - - {% endif %} -
    - - {% if timeline is not null %} -

    {{"Timeline"|trans}}

    - {{ timeline|raw }} - {% endif %} - - - -
    + + {% include 'ChillTaskBundle:SingleTask:_show.html.twig' %} {% endblock %} diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/showCourseTask.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/showCourseTask.html.twig new file mode 100644 index 000000000..643617a55 --- /dev/null +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/showCourseTask.html.twig @@ -0,0 +1,16 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + + +{% set activeRouteKey = 'chill_task_single_task_show' %} +{% set accompanyingCourse = task.course %} + +{% block title %} + {{ 'Task'|trans }} +{% endblock %} + + +{% block content %} + + {% include 'ChillTaskBundle:SingleTask:_show.html.twig' %} + +{% endblock %} diff --git a/src/Bundle/ChillTaskBundle/translations/messages.fr.yml b/src/Bundle/ChillTaskBundle/translations/messages.fr.yml index 71bc22612..7af9d450d 100644 --- a/src/Bundle/ChillTaskBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillTaskBundle/translations/messages.fr.yml @@ -1,53 +1,54 @@ -Tasks: 'Tâches' -'New task': 'Nouvelle tâche' -'Add a new task': 'Ajouter une nouvelle tâche' +Tasks: "Tâches" +"New task": "Nouvelle tâche" +"Add a new task": "Ajouter une nouvelle tâche" Title: Titre Description: Description -Assignee: 'Personne assignée' +Assignee: "Personne assignée" Scope: Cercle -'Start date': 'Date de début' -'End date': "Date d'échéance" -'Warning date': "Date d'avertissement" -'Warning interval': "Délai d'avertissement avant la date d'échéance" -'Unknown dates': 'Dates non spécifiées' -'N': '' -'Unit': '' +"Start date": "Date de début" +"End date": "Date d'échéance" +"Warning date": "Date d'avertissement" +"Warning interval": "Délai d'avertissement avant la date d'échéance" +"Unknown dates": "Dates non spécifiées" +"N": "" +"Unit": "" Task: Tâche Details: Détails Person: Personne Date: Date Dates: Dates User: Utilisateur -'Task list': 'Liste des tâches' -'Tasks with expired deadline': "Tâches avec une date d'échéance dépassée" -'Tasks with warning deadline reached': "Tâches avec une date d'avertissement atteinte" -'Current tasks': 'Tâches en cours' -'Closed tasks': Tâches terminées -'Tasks not started': 'Tâches non commencées' -'Task start date': 'Date de début' -'Task warning date': "Date d'avertissement" -'Task end date': "Date d'échéance" -'Start': 'Début' -'Warning': 'Avertissement' -'End': 'Échéance' -'Task type': 'Type' -'Task status': 'Statut' -'Edit the task': 'Modifier la tâche' -'Edit task': 'Modifier la tâche' -'Save task': 'Enregistrer la tâche' -'View the task': 'Voir la tâche' -'Update the task': 'Mettre à jour la tâche' -'Remove task': 'Supprimer la tâche' -'Delete': 'Supprimer' -'Change task status': 'Changer le statut' +"Task list": "Liste des tâches" +"Tasks with expired deadline": "Tâches avec une date d'échéance dépassée" +"Tasks with warning deadline reached": "Tâches avec une date d'avertissement atteinte" +"Current tasks": "Tâches en cours" +"Closed tasks": Tâches terminées +"Tasks not started": "Tâches non commencées" +"Task start date": "Date de début" +"Task warning date": "Date d'avertissement" +"Task end date": "Date d'échéance" +"Start": "Début" +"Warning": "Avertissement" +"End": "Échéance" +"Task type": "Type" +"Task status": "Statut" +"Edit the task": "Modifier la tâche" +"Edit task": "Modifier la tâche" +"Save task": "Enregistrer la tâche" +"View the task": "Voir la tâche" +"Update the task": "Mettre à jour la tâche" +"Remove task": "Supprimer la tâche" +"Delete": "Supprimer" +"Change task status": "Changer le statut" 'Are you sure you want to remove the task about "%name%" ?': 'Êtes-vous sûr·e de vouloir supprimer la tâche de "%name%"?' -'See more': 'Voir plus' -'Associated tasks': 'Tâches associées' -'My tasks': 'Mes tâches' -'No description': 'Pas de description' -'No dates specified': 'Dates non spécifiées' -'No one assignee': 'Aucune personne assignée' -'Task types': Types de tâches +"See more": "Voir plus" +"Associated tasks": "Tâches associées" +"My tasks": "Mes tâches" +"Tasks for this accompanying period": "Tâches pour ce parcours d'accompagnement" +"No description": "Pas de description" +"No dates specified": "Dates non spécifiées" +"No one assignee": "Aucune personne assignée" +"Task types": Types de tâches Days: Jour(s) Weeks: Semaine(s) Months: Mois @@ -63,36 +64,36 @@ For person: Pour By: Par # transitions - default task definition -'new': 'nouvelle' -'in_progress': 'en cours' -'closed': 'fermée' -'canceled': 'supprimée' +"new": "nouvelle" +"in_progress": "en cours" +"closed": "fermée" +"canceled": "supprimée" start: démarrer close: clotûrer cancel: annuler Start_verb: Démarrer Close_verb: Clotûrer Set this task to cancel state: Marquer cette tâche comme annulée -'%user% has closed the task': '%user% a fermé la tâche' -'%user% has canceled the task': '%user% a annulé la tâche' -'%user% has started the task': '%user% a commencé la tâche' -'%user% has created the task': '%user% a introduit la tâche' +"%user% has closed the task": "%user% a fermé la tâche" +"%user% has canceled the task": "%user% a annulé la tâche" +"%user% has started the task": "%user% a commencé la tâche" +"%user% has created the task": "%user% a introduit la tâche" Are you sure you want to close this task ?: Êtes-vous sûrs de vouloir clotûrer cette tâche ? Are you sure you want to cancel this task ?: Êtes-vous sûrs de vouloir annuler cette tâche ? Are you sure you want to start this task ?: Êtes-vous sûrs de vouloir démarrer cette tâche ? #Flash messages -'The task is created': 'La tâche a été créée' -'There is no tasks.': Aucune tâche. -'The task has been successfully removed.': 'La tâche a bien été supprimée' -'This form contains errors': 'Ce formulaire contient des erreurs' -'The task has been updated': 'La tâche a été mise à jour' -'The transition is successfully applied': 'La transition a bien été effectuée' -'The transition could not be applied': "La transition n'a pas pu être appliquée" +"The task is created": "La tâche a été créée" +"There is no tasks.": Aucune tâche. +"The task has been successfully removed.": "La tâche a bien été supprimée" +"This form contains errors": "Ce formulaire contient des erreurs" +"The task has been updated": "La tâche a été mise à jour" +"The transition is successfully applied": "La transition a bien été effectuée" +"The transition could not be applied": "La transition n'a pas pu être appliquée" #widget -'%number% tasks over deadline': '{0} Aucune tâche dépassée|{1} Une tâche dépassée | ]1,Inf[ %count% tâches dépassées' -'%number% tasks near deadline': '{0} Aucune tâche en rappel|{1} Une tâche en rappel | ]1,Inf[ %count% tâches en rappel' +"%number% tasks over deadline": "{0} Aucune tâche dépassée|{1} Une tâche dépassée | ]1,Inf[ %count% tâches dépassées" +"%number% tasks near deadline": "{0} Aucune tâche en rappel|{1} Une tâche en rappel | ]1,Inf[ %count% tâches en rappel" #title My tasks near deadline: Mes tâches à échéance proche @@ -107,4 +108,4 @@ All centers: Tous les centres CHILL_TASK_TASK_CREATE: Ajouter une tâche CHILL_TASK_TASK_DELETE: Supprimer une tâche CHILL_TASK_TASK_SHOW: Voir une tâche -CHILL_TASK_TASK_UPDATE: Modifier une tâche \ No newline at end of file +CHILL_TASK_TASK_UPDATE: Modifier une tâche From 01ae50aca75122d3c53d8d983d880c5c1a726aed Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 17 Sep 2021 14:33:42 +0200 Subject: [PATCH 07/10] new/show/edit/delete/list functionality added for accompanyingperiod task --- .../Entity/AccompanyingPeriod.php | 10 ++ .../Controller/SingleTaskController.php | 143 ++++++++++++------ .../ChillTaskBundle/Entity/AbstractTask.php | 12 ++ .../ChillTaskBundle/Form/SingleTaskType.php | 7 +- ...{PersonMenuBuilder.php => MenuBuilder.php} | 0 .../views/SingleTask/_edit.html.twig | 25 +++ .../Resources/views/SingleTask/_new.html.twig | 30 ++++ .../views/SingleTask/_show.html.twig | 4 +- .../confirm_deleteCourseTask.html.twig | 19 +++ .../Resources/views/SingleTask/edit.html.twig | 39 +---- .../views/SingleTask/editCourseTask.html.twig | 14 ++ .../Resources/views/SingleTask/new.html.twig | 33 +--- .../views/SingleTask/newCourseTask.html.twig | 12 ++ .../Security/Authorization/TaskVoter.php | 13 +- .../translations/messages.fr.yml | 1 + 15 files changed, 243 insertions(+), 119 deletions(-) rename src/Bundle/ChillTaskBundle/Menu/{PersonMenuBuilder.php => MenuBuilder.php} (100%) create mode 100644 src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_edit.html.twig create mode 100644 src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_new.html.twig create mode 100644 src/Bundle/ChillTaskBundle/Resources/views/SingleTask/confirm_deleteCourseTask.html.twig create mode 100644 src/Bundle/ChillTaskBundle/Resources/views/SingleTask/editCourseTask.html.twig create mode 100644 src/Bundle/ChillTaskBundle/Resources/views/SingleTask/newCourseTask.html.twig diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 1c375d051..0458a1e74 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -26,6 +26,7 @@ use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface; use Chill\MainBundle\Doctrine\Model\TrackCreationInterface; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Entity\Center; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive; use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; @@ -967,6 +968,15 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface return $this->addressLocation; } + public function getCenter(): ?Center + { + if (count($this->getPersons()) === 0){ + return null; + } else { + return $this->getPersons()->first()->getCenter(); + } + } + /** * @Groups({"write"}) */ diff --git a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php index e98688aa6..456699091 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -6,7 +6,6 @@ use Chill\PersonBundle\Privacy\PrivacyEvent; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; -use Doctrine\ORM\EntityManager; use Chill\PersonBundle\Entity\Person; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -22,7 +21,6 @@ use Chill\TaskBundle\Repository\SingleTaskRepository; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\PersonBundle\Repository\PersonRepository; -use Chill\MainBundle\Entity\UserRepository; use Chill\TaskBundle\Event\TaskEvent; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Translation\TranslatorInterface; @@ -32,8 +30,6 @@ use Chill\MainBundle\Timeline\TimelineBuilder; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Repository\AccompanyingPeriodRepository; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; -use Chill\TaskBundle\Form\SingleTaskCourseType; -use Chill\TaskBundle\Repository\AbstractTaskRepository; use Symfony\Component\HttpFoundation\RequestStack; /** @@ -205,6 +201,7 @@ class SingleTaskController extends AbstractController 'task' => $task, 'accompanyingCourse' => $course, )); + break; } } @@ -281,8 +278,9 @@ class SingleTaskController extends AbstractController $timeline = $this->timelineBuilder ->getTimelineHTML('task', array('task' => $task)); + - if($this->getEntityContext() === 'person'){ + if($task->getContext() instanceof Person){ return $this->render('ChillTaskBundle:SingleTask:show.html.twig', array( 'task' => $task, 'timeline' => $timeline @@ -311,7 +309,7 @@ class SingleTaskController extends AbstractController $em = $this->getDoctrine()->getManager(); $task = $em->getRepository(SingleTask::class)->find($id); - if ($task->getPerson() !== null) { + if ($task->getContext() instanceof Person) { $personId = $task->getPerson()->getId(); if ($personId === null) { return new Response("You must provide a person_id", Response::HTTP_BAD_REQUEST); @@ -324,7 +322,21 @@ class SingleTaskController extends AbstractController if ($person === null) { throw $this->createNotFoundException("Invalid person id"); } + } else { + $courseId = $task->getCourse()->getId(); + if ($courseId === null) { + return new Response("You must provide a course_id", Response::HTTP_BAD_REQUEST); + } + + $course = $this->getDoctrine()->getManager() + ->getRepository(AccompanyingPeriod::class) + ->find($courseId); + + if ($course === null) { + throw $this->createNotFoundException("Invalid accompanying period id"); + } } + $this->denyAccessUnlessGranted(TaskVoter::UPDATE, $task, 'You are not ' . 'allowed to edit this task'); @@ -351,19 +363,25 @@ class SingleTaskController extends AbstractController $this->addFlash('success', $translator ->trans("The task has been updated")); - - $event = new PrivacyEvent($person, array( + + if($task->getContext() instanceof Person){ + $event = new PrivacyEvent($person, array( 'element_class' => SingleTask::class, 'element_id' => $task->getId(), 'action' => 'update' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->redirectToRoute( - 'chill_task_singletask_list', - $this->request->query->get('list_params', []) - ); + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + return $this->redirectToRoute( + 'chill_task_singletask_list', + $this->request->query->get('list_params', []) + ); + } else { + return $this->redirectToRoute( + 'chill_task_singletask_courselist', + $this->request->query->get('list_params', []) + ); + } } else { $this->addFlash('error', $translator->trans("This form contains errors")); } @@ -375,17 +393,26 @@ class SingleTaskController extends AbstractController return $event->getResponse(); } - $event = new PrivacyEvent($person, array( - 'element_class' => SingleTask::class, - 'element_id' => $task->getId(), - 'action' => 'edit' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render('ChillTaskBundle:SingleTask:edit.html.twig', array( - 'task' => $task, - 'form' => $form->createView() - )); + if($task->getContext() instanceof Person){ + $event = new PrivacyEvent($person, array( + 'element_class' => SingleTask::class, + 'element_id' => $task->getId(), + 'action' => 'edit' + )); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render('ChillTaskBundle:SingleTask:edit.html.twig', array( + 'task' => $task, + 'form' => $form->createView() + )); + } else { + return $this->render('ChillTaskBundle:SingleTask:editCourseTask.html.twig', array( + 'task' => $task, + 'form' => $form->createView(), + 'accompanyingCourse' => $course + )); + } + } @@ -422,8 +449,22 @@ class SingleTaskController extends AbstractController throw $this->createNotFoundException("Invalid person id"); } + } else { + $courseId = $task->getCourse()->getId(); + if ($courseId === null){ + return new Response("You must provide a course_id", Response::HTTP_BAD_REQUEST); + } + + $course = $this->getDoctrine()->getManager() + ->getRepository(AccompanyingPeriod::class) + ->find($courseId); + + if($course === null){ + throw $this->createNotFoundException("Invalid accompanying period id"); + } } + $this->denyAccessUnlessGranted(TaskVoter::DELETE, $task, 'You are not ' . 'allowed to delete this task'); @@ -452,19 +493,35 @@ class SingleTaskController extends AbstractController $this->addFlash('success', $translator ->trans("The task has been successfully removed.")); - return $this->redirect($this->generateUrl( - 'chill_task_singletask_list', - $request->query->get('list_params', [ - 'person_id' => $person->getId() - ]))); + if($task->getContext() instanceof Person){ + return $this->redirect($this->generateUrl( + 'chill_task_singletask_list', + $request->query->get('list_params', [ + 'person_id' => $person->getId() + ]))); + } else { + return $this->redirect($this->generateUrl( + 'chill_task_singletask_courselist', + $request->query->get('list_params', [ + 'course_id' => $course->getId() + ]))); + } } } + if($task->getContext() instanceof Person){ + return $this->render('ChillTaskBundle:SingleTask:confirm_delete.html.twig', array( + 'task' => $task, + 'delete_form' => $form->createView() + )); + } else { + return $this->render('ChillTaskBundle:SingleTask:confirm_deleteCourseTask.html.twig', array( + 'task' => $task, + 'delete_form' => $form->createView(), + 'accompanyingCourse' => $course + )); + } - return $this->render('ChillTaskBundle:SingleTask:confirm_delete.html.twig', array( - 'task' => $task, - 'delete_form' => $form->createView() - )); } /** @@ -475,18 +532,10 @@ class SingleTaskController extends AbstractController */ protected function setCreateForm(SingleTask $task, Role $role) { - if($this->getEntityContext() === 'person'){ - $form = $this->createForm(SingleTaskType::class, $task, [ - 'center' => $task->getCenter(), - 'role' => $role, - ]); - } - - if($this->getEntityContext() === 'course'){ - $form = $this->createForm(SingleTaskCourseType::class, $task, [ - 'center' => $task->getCenter(), - ]); - } + $form = $this->createForm(SingleTaskType::class, $task, [ + 'center' => $task->getCenter(), + 'role' => $role, + ]); $form->add('submit', SubmitType::class); diff --git a/src/Bundle/ChillTaskBundle/Entity/AbstractTask.php b/src/Bundle/ChillTaskBundle/Entity/AbstractTask.php index 649de0422..57a194ef8 100644 --- a/src/Bundle/ChillTaskBundle/Entity/AbstractTask.php +++ b/src/Bundle/ChillTaskBundle/Entity/AbstractTask.php @@ -248,11 +248,23 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface { if ($this->getPerson() instanceof Person) { return $this->getPerson()->getCenter(); + } else { + return $this->getCourse()->getCenter(); } return null; } + + public function getContext() + { + // if ($this->getCourse() instanceof AccompanyingPeriod){ + // return $this->getCourse(); + // } else { + // return $this->getPerson(); + // } + return $this->getPerson() ?? $this->getCourse(); + } public function getScope(): ?\Chill\MainBundle\Entity\Scope { diff --git a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php index 16f000aa2..5802512b7 100644 --- a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php +++ b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php @@ -48,11 +48,11 @@ class SingleTaskType extends AbstractType 'center' => $options['center'], 'role' => $options['role'], 'placeholder' => 'Not assigned' - ]) + ]) ->add('circle', ScopePickerType::class, [ 'center' => $options['center'], 'role' => $options['role'] - ]) + ]) ->add('startDate', ChillDateType::class, [ 'required' => false ]) @@ -61,8 +61,7 @@ class SingleTaskType extends AbstractType ]) ->add('warningInterval', DateIntervalType::class, [ 'required' => false - ]) - ; + ]); } public function configureOptions(OptionsResolver $resolver) diff --git a/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php similarity index 100% rename from src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php rename to src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_edit.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_edit.html.twig new file mode 100644 index 000000000..98b070114 --- /dev/null +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_edit.html.twig @@ -0,0 +1,25 @@ +
    + +

    {{ 'Edit task'|trans }}

    + + {{ form_start(form) }} + + {{ form_row(form.title) }} + {{ form_row(form.description) }} + {{ form_row(form.assignee) }} + {{ form_row(form.circle) }} + {{ form_row(form.startDate) }} + {{ form_row(form.endDate) }} + {{ form_row(form.warningInterval) }} + +
      +
    • + + {{ 'Cancel'|trans }} +
    • +
    • + {{ form_widget(form.submit, { 'label': 'Save task', 'attr': {'class' : 'btn btn-update'}})}} +
    • +
    + {{ form_end(form) }} +
    diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_new.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_new.html.twig new file mode 100644 index 000000000..7cb19b19f --- /dev/null +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_new.html.twig @@ -0,0 +1,30 @@ +
    + +

    {{ 'New task'|trans }}

    + + {{ form_start(form) }} + + {{ form_errors(form) }} + + {{ form_row(form.title) }} + {{ form_row(form.description) }} + {{ form_row(form.assignee) }} + {{ form_row(form.circle) }} + {{ form_row(form.startDate) }} + {{ form_row(form.endDate) }} + {{ form_row(form.warningInterval) }} + +
      +
    • + + {{'Cancel'|trans}} + +
    • +
    • + {{ form_widget(form.submit, { 'label': 'Add a new task'|trans, 'attr': {'class': 'btn btn-save'} }) }} +
    • +
    + + {{ form_end(form) }} + +
    diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_show.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_show.html.twig index a8905285a..f73f2740d 100644 --- a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_show.html.twig +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/_show.html.twig @@ -68,8 +68,8 @@
    • - - {{ app.request.query.get('returnLabel')|default('Back to the list'|trans) }} + + {{'Back to the list'|trans}}
    • diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/confirm_deleteCourseTask.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/confirm_deleteCourseTask.html.twig new file mode 100644 index 000000000..49857188c --- /dev/null +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/confirm_deleteCourseTask.html.twig @@ -0,0 +1,19 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = 'chill_task_task_list' %} +{% set course = task.course %} + +{% block title 'Remove task'|trans %} + +{% block content %} + + {{ include('@ChillMain/Util/confirmation_template.html.twig', + { + 'title' : 'Remove task'|trans, + 'confirm_question' : 'Are you sure you want to remove the task about accompanying period "%id%" ?'|trans({ '%id%' : course.id } ), + 'cancel_route' : 'chill_task_singletask_courselist', + 'cancel_parameters' : app.request.query.get('list_params', { } ), + 'form' : delete_form, + } ) }} + +{% endblock %} diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/edit.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/edit.html.twig index 67604f015..590740cf0 100644 --- a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/edit.html.twig +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/edit.html.twig @@ -14,46 +14,17 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "@ChillPerson/Person/layout.html.twig" %} +{% extends person is defined ? "@ChillPerson/Person/layout.html.twig" %} {% set activeRouteKey = 'chill_task_single_task_edit' %} {% set person = task.person %} -{% block title %}{{ 'Edit task'|trans }}{% endblock %} +{% block title %} + {{ 'Edit task'|trans }} +{% endblock %} {% block personcontent %} -
      - -

      {{ 'Edit task'|trans }}

      - {{ form_start(form) }} + {% include 'ChillTaskBundle:SingleTask:_edit.html.twig' %} - {{ form_row(form.title) }} - {{ form_row(form.description) }} - {{ form_row(form.assignee) }} - {{ form_row(form.circle) }} - {{ form_row(form.startDate) }} - {{ form_row(form.endDate) }} - {{ form_row(form.warningInterval) }} - - - - {{ form_end(form) }} - -
      {% endblock %} diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/editCourseTask.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/editCourseTask.html.twig new file mode 100644 index 000000000..1805761ae --- /dev/null +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/editCourseTask.html.twig @@ -0,0 +1,14 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = 'chill_task_single_task_edit' %} +{% set course = task.course %} + +{% block title %} + {{ 'Edit task'|trans }} +{% endblock %} + +{% block content %} + + {% include 'ChillTaskBundle:SingleTask:_edit.html.twig' %} + +{% endblock %} diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/new.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/new.html.twig index 8f6ba2a4b..2b59fd5bf 100644 --- a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/new.html.twig +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/new.html.twig @@ -14,37 +14,16 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} -{% extends "@ChillPerson/Person/layout.html.twig" %} +{% extends person is defined ? "@ChillPerson/Person/layout.html.twig" : "@ChillPerson/AccompanyingCourse/layout.html.twig" %} {% set activeRouteKey = 'chill_task_single_task_new' %} {% set person = task.person %} -{% block title %}{{ 'New task'|trans }}{% endblock %} +{% block title %} + {{ 'New task'|trans }} +{% endblock %} + {% block personcontent %} -
      - -

      {{ 'New task'|trans }}

      - - {{ form_start(form) }} - - {{ form_errors(form) }} - - {{ form_row(form.title) }} - {{ form_row(form.description) }} - {{ form_row(form.assignee) }} - {{ form_row(form.circle) }} - {{ form_row(form.startDate) }} - {{ form_row(form.endDate) }} - {{ form_row(form.warningInterval) }} - -
        -
      • - {{ form_widget(form.submit, { 'label': 'Add a new task'|trans, 'attr': {'class': 'btn btn-save'} }) }} -
      • -
      - - {{ form_end(form) }} - -
      + {% include 'ChillTaskBundle:SingleTask:_new.html.twig' %} {% endblock %} diff --git a/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/newCourseTask.html.twig b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/newCourseTask.html.twig new file mode 100644 index 000000000..083c0795c --- /dev/null +++ b/src/Bundle/ChillTaskBundle/Resources/views/SingleTask/newCourseTask.html.twig @@ -0,0 +1,12 @@ +{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %} + +{% set activeRouteKey = 'chill_task_single_task_new' %} +{# {% set person = task.person %} #} + +{% block title %} + {{ 'New task'|trans }} +{% endblock %} + +{% block content %} + {% include 'ChillTaskBundle:SingleTask:_new.html.twig' %} +{% endblock %} diff --git a/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php b/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php index 8b8bce839..1da58c5ce 100644 --- a/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php +++ b/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php @@ -27,7 +27,9 @@ use Psr\Log\LoggerInterface; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Chill\MainBundle\Entity\User; +use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Chill\TaskBundle\Security\Authorization\AuthorizationEvent; @@ -128,14 +130,13 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf } if ($subject instanceof AbstractTask) { - if ($subject->getPerson() === null) { + $associated = $subject->getPerson() ?? $subject->getCourse(); + if ($associated === null) { throw new \LogicException("You should associate a person with task " . "in order to check autorizations"); } - - $person = $subject->getPerson(); } elseif ($subject instanceof Person) { - $person = $subject; + $associated = $subject; } else { // subject is null. We check that at least one center is reachable $centers = $this->authorizationHelper->getReachableCenters($token->getUser(), new Role($attribute)); @@ -143,8 +144,10 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf return count($centers) > 0; } - if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { + if ($associated instanceof Person && !$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $associated)) { + return false; + } elseif ($associated instanceof AccompanyingPeriod && !$this->accessDecisionManager->decide($token, [AccompanyingPeriodVoter::SEE], $associated)) { return false; } diff --git a/src/Bundle/ChillTaskBundle/translations/messages.fr.yml b/src/Bundle/ChillTaskBundle/translations/messages.fr.yml index 7af9d450d..50af895e7 100644 --- a/src/Bundle/ChillTaskBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillTaskBundle/translations/messages.fr.yml @@ -41,6 +41,7 @@ User: Utilisateur "Delete": "Supprimer" "Change task status": "Changer le statut" 'Are you sure you want to remove the task about "%name%" ?': 'Êtes-vous sûr·e de vouloir supprimer la tâche de "%name%"?' +'Are you sure you want to remove the task about accompanying period "%id%" ?': 'Êtes-vous sûr·e de vouloir supprimer la tâche du parcours "%id%"?' "See more": "Voir plus" "Associated tasks": "Tâches associées" "My tasks": "Mes tâches" From 17b6f287dc03f77f43ba3e30e4ede8ef0a7165a5 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 17 Sep 2021 14:49:43 +0200 Subject: [PATCH 08/10] Changed name of PersonMenuBuilder More general name since it also contains the AccompanyingPeriod task menu entry now. --- .../ChillTaskBundle/Menu/MenuBuilder.php | 8 ++-- .../ChillTaskBundle/config/services/menu.yaml | 44 +++++++++---------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php b/src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php index 26f06d1b2..9b1890958 100644 --- a/src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php +++ b/src/Bundle/ChillTaskBundle/Menu/MenuBuilder.php @@ -28,7 +28,7 @@ use Symfony\Component\Translation\TranslatorInterface; * * @author Julien Fastré */ -class PersonMenuBuilder implements LocalMenuBuilderInterface +class MenuBuilder implements LocalMenuBuilderInterface { /** * @@ -86,12 +86,10 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface public function buildAccompanyingCourseMenu($menu, $parameters){ - //var $person \Chill\PersonBundle\Entity\Person */ $course = $parameters['accompanyingCourse']; - //TODO: implement voter again? - // if ($this->authorizationChecker->isGranted(TaskVoter::SHOW, $course)) { + if ($this->authorizationChecker->isGranted(TaskVoter::SHOW, $course)) { $menu->addChild( $this->translator->trans('Tasks'), [ 'route' => 'chill_task_singletask_courselist', @@ -99,7 +97,7 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface [ 'course_id' => $course->getId() ] ]) ->setExtra('order', 400); - // } + } } public static function getMenuIds(): array diff --git a/src/Bundle/ChillTaskBundle/config/services/menu.yaml b/src/Bundle/ChillTaskBundle/config/services/menu.yaml index b4ff7a421..75726fcf4 100644 --- a/src/Bundle/ChillTaskBundle/config/services/menu.yaml +++ b/src/Bundle/ChillTaskBundle/config/services/menu.yaml @@ -1,23 +1,23 @@ services: - Chill\TaskBundle\Menu\UserMenuBuilder: - arguments: - $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface' - $counter: '@Chill\TaskBundle\Templating\UI\CountNotificationTask' - $translator: '@Symfony\Component\Translation\TranslatorInterface' - $authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface' - tags: - - { name: 'chill.menu_builder' } - - Chill\TaskBundle\Menu\PersonMenuBuilder: - arguments: - $authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface' - $translator: '@Symfony\Component\Translation\TranslatorInterface' - tags: - - { name: 'chill.menu_builder' } - - Chill\TaskBundle\Menu\SectionMenuBuilder: - arguments: - $authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface' - $translator: '@Symfony\Component\Translation\TranslatorInterface' - tags: - - { name: 'chill.menu_builder' } + Chill\TaskBundle\Menu\UserMenuBuilder: + arguments: + $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface' + $counter: '@Chill\TaskBundle\Templating\UI\CountNotificationTask' + $translator: '@Symfony\Component\Translation\TranslatorInterface' + $authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface' + tags: + - { name: "chill.menu_builder" } + + Chill\TaskBundle\Menu\MenuBuilder: + arguments: + $authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface' + $translator: '@Symfony\Component\Translation\TranslatorInterface' + tags: + - { name: "chill.menu_builder" } + + Chill\TaskBundle\Menu\SectionMenuBuilder: + arguments: + $authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface' + $translator: '@Symfony\Component\Translation\TranslatorInterface' + tags: + - { name: "chill.menu_builder" } From 27a52ce1666637ebefd0d6438a8383ba7ec20995 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 17 Sep 2021 14:53:15 +0200 Subject: [PATCH 09/10] Fix SingleTaskListType accompanyingCourse also defined as a form option --- src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php b/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php index 99e8ddb42..634035f96 100644 --- a/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php +++ b/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php @@ -284,6 +284,7 @@ class SingleTaskListType extends AbstractType ->setDefined('person') ->setDefault('person', null) ->setAllowedTypes('person', [Person::class, 'null']) + ->setDefined('accompanyingCourse') ->setDefined('add_status') ->setDefault('add_status', false) ->setAllowedTypes('add_status', ['bool']) From 7515415888f4f99060de05f6ed8e9731eb7d58ec Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Fri, 17 Sep 2021 15:17:13 +0200 Subject: [PATCH 10/10] autowire and configure MenuBuilder --- src/Bundle/ChillTaskBundle/config/services/menu.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Bundle/ChillTaskBundle/config/services/menu.yaml b/src/Bundle/ChillTaskBundle/config/services/menu.yaml index 75726fcf4..a9e1948d6 100644 --- a/src/Bundle/ChillTaskBundle/config/services/menu.yaml +++ b/src/Bundle/ChillTaskBundle/config/services/menu.yaml @@ -9,9 +9,8 @@ services: - { name: "chill.menu_builder" } Chill\TaskBundle\Menu\MenuBuilder: - arguments: - $authorizationChecker: '@Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface' - $translator: '@Symfony\Component\Translation\TranslatorInterface' + autowire: true + autoconfigure: true tags: - { name: "chill.menu_builder" }