From b4de51a60181fd1ded2fd7c8c13e296333e10d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sun, 8 Jul 2018 22:37:51 +0200 Subject: [PATCH] entry "task list" in person menu is dynamic - based on ACL --- Controller/SingleTaskController.php | 6 +-- Menu/PersonMenuBuilder.php | 81 ++++++++++++++++++++++++++++ Resources/config/services/menu.yml | 7 +++ Security/Authorization/TaskVoter.php | 13 ++++- 4 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 Menu/PersonMenuBuilder.php diff --git a/Controller/SingleTaskController.php b/Controller/SingleTaskController.php index 4e3662a9e..2125bb2f3 100644 --- a/Controller/SingleTaskController.php +++ b/Controller/SingleTaskController.php @@ -338,11 +338,7 @@ class SingleTaskController extends Controller * * @Route( * "/{_locale}/task/singletask/list", - * name="chill_task_singletask_list", - * options={ "menus": { - * "person" : { "order": 400, "label": "Associated tasks" } , - * "section": { "order": 400, "label": "Tasks", "icons": "tasks" } - * }} + * name="chill_task_singletask_list" * ) */ public function listAction( diff --git a/Menu/PersonMenuBuilder.php b/Menu/PersonMenuBuilder.php new file mode 100644 index 000000000..199645aa5 --- /dev/null +++ b/Menu/PersonMenuBuilder.php @@ -0,0 +1,81 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +namespace Chill\TaskBundle\Menu; + +use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Knp\Menu\MenuItem; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Chill\TaskBundle\Security\Authorization\TaskVoter; +use Symfony\Component\Translation\TranslatorInterface; + +/** + * + * + * @author Julien Fastré + */ +class PersonMenuBuilder implements LocalMenuBuilderInterface +{ + /** + * + * @var TranslatorInterface + */ + protected $translator; + + /** + * + * @var AuthorizationCheckerInterface + */ + protected $authorizationChecker; + + public function __construct( + AuthorizationCheckerInterface $authorizationChecker, + TranslatorInterface $translator) + { + $this->translator = $translator; + $this->authorizationChecker = $authorizationChecker; + } + + + public function buildMenu($menuId, MenuItem $menu, array $parameters) + { + /* @var $person \Chill\PersonBundle\Entity\Person */ + $person = $parameters['person'] ?? null; + + if ($this->authorizationChecker->isGranted(TaskVoter::SHOW, $person)) { + $menu->addChild( + $this->translator->trans( + $menuId === 'person' ? 'Associated tasks' : 'Tasks'), [ + 'route' => 'chill_task_singletask_list', + 'routeParameters' => $menuId === 'person' ? + [ 'person_id' => $person->getId() ] + : + null, + ]) + ->setExtra('order', 400) + ; + if ($menuId === 'section') { + $menu->setExtra('icons', 'tasks'); + } + } + } + + public static function getMenuIds(): array + { + return ['person']; + } +} diff --git a/Resources/config/services/menu.yml b/Resources/config/services/menu.yml index d1c8344aa..cbaded857 100644 --- a/Resources/config/services/menu.yml +++ b/Resources/config/services/menu.yml @@ -6,3 +6,10 @@ services: $translator: '@Symfony\Component\Translation\TranslatorInterface' 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' } diff --git a/Security/Authorization/TaskVoter.php b/Security/Authorization/TaskVoter.php index c28fcf942..ad8895892 100644 --- a/Security/Authorization/TaskVoter.php +++ b/Security/Authorization/TaskVoter.php @@ -28,6 +28,7 @@ use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\Person; +use Symfony\Component\Security\Core\Role\Role; /** * @@ -80,7 +81,10 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf { return ($subject instanceof AbstractTask && in_array($attribute, self::ROLES)) || - ($subject instanceof Person && $attribute === self::CREATE); + ($subject instanceof Person && \in_array($attribute, [ self::CREATE, self::SHOW ])) + || + (NULL === $subject && $attribute === self::SHOW ) + ; } /** @@ -105,8 +109,13 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf } $person = $subject->getPerson(); - } else { + } elseif ($subject instanceof Person) { $person = $subject; + } else { + // subject is null. We check that at least one center is reachable + $centers = $this->authorizationHelper->getReachableCenters($token->getUser(), new Role($attribute)); + + return count($centers) > 0; } if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) {