diff --git a/src/Bundle/ChillMainBundle/Tests/Workflow/EventSubscriber/EntityWorkflowGuardTransitionTest.php b/src/Bundle/ChillMainBundle/Tests/Workflow/EventSubscriber/EntityWorkflowGuardTransitionTest.php index bccd6cf9e..dd3b12e86 100644 --- a/src/Bundle/ChillMainBundle/Tests/Workflow/EventSubscriber/EntityWorkflowGuardTransitionTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Workflow/EventSubscriber/EntityWorkflowGuardTransitionTest.php @@ -13,6 +13,7 @@ namespace Chill\MainBundle\Tests\Workflow\EventSubscriber; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Workflow\EntityWorkflow; +use Chill\MainBundle\Security\Authorization\EntityWorkflowTransitionVoter; use Chill\MainBundle\Templating\Entity\UserRender; use Chill\MainBundle\Workflow\EntityWorkflowMarkingStore; use Chill\MainBundle\Workflow\EventSubscriber\EntityWorkflowGuardTransition; @@ -84,12 +85,14 @@ class EntityWorkflowGuardTransitionTest extends TestCase /** * @dataProvider provideBlockingTransition */ - public function testTransitionGuardBlocked(EntityWorkflow $entityWorkflow, string $transition, ?User $user, string $uuid): void + public function testTransitionGuardBlocked(EntityWorkflow $entityWorkflow, string $transition, ?User $user, bool $isGrantedAllTransition, string $uuid): void { $userRender = $this->prophesize(UserRender::class); $userRender->renderString(Argument::type(User::class), [])->willReturn('user-as-string'); $security = $this->prophesize(Security::class); $security->getUser()->willReturn($user); + $security->isGranted(EntityWorkflowTransitionVoter::APPLY_ALL_TRANSITIONS, $entityWorkflow->getCurrentStep()) + ->willReturn($isGrantedAllTransition); $transitionGuard = new EntityWorkflowGuardTransition($userRender->reveal(), $security->reveal()); $registry = self::buildRegistry($transitionGuard); @@ -115,12 +118,14 @@ class EntityWorkflowGuardTransitionTest extends TestCase /** * @dataProvider provideValidTransition */ - public function testTransitionGuardValid(EntityWorkflow $entityWorkflow, string $transition, ?User $user, string $newStep): void + public function testTransitionGuardValid(EntityWorkflow $entityWorkflow, string $transition, ?User $user, bool $isGrantedAllTransition, string $newStep): void { $userRender = $this->prophesize(UserRender::class); $userRender->renderString(Argument::type(User::class), [])->willReturn('user-as-string'); $security = $this->prophesize(Security::class); $security->getUser()->willReturn($user); + $security->isGranted(EntityWorkflowTransitionVoter::APPLY_ALL_TRANSITIONS, $entityWorkflow->getCurrentStep()) + ->willReturn($isGrantedAllTransition); $transitionGuard = new EntityWorkflowGuardTransition($userRender->reveal(), $security->reveal()); $registry = self::buildRegistry($transitionGuard); @@ -135,20 +140,25 @@ class EntityWorkflowGuardTransitionTest extends TestCase public static function provideBlockingTransition(): iterable { - yield [self::buildEntityWorkflow([new User()]), 'transition1', new User(), 'f3eeb57c-7532-11ec-9495-e7942a2ac7bc']; - yield [self::buildEntityWorkflow([]), 'transition1', null, 'd9e39a18-704c-11ef-b235-8fe0619caee7']; - yield [self::buildEntityWorkflow([new User()]), 'transition1', null, 'd9e39a18-704c-11ef-b235-8fe0619caee7']; - yield [self::buildEntityWorkflow([$user = new User()]), 'transition3', $user, '5b6b95e0-704d-11ef-a5a9-4b6fc11a8eeb']; + yield [self::buildEntityWorkflow([new User()]), 'transition1', new User(), false, 'f3eeb57c-7532-11ec-9495-e7942a2ac7bc']; + yield [self::buildEntityWorkflow([]), 'transition1', null, false, 'd9e39a18-704c-11ef-b235-8fe0619caee7']; + yield [self::buildEntityWorkflow([new User()]), 'transition1', null, false, 'd9e39a18-704c-11ef-b235-8fe0619caee7']; + yield [self::buildEntityWorkflow([$user = new User()]), 'transition3', $user, false, '5b6b95e0-704d-11ef-a5a9-4b6fc11a8eeb']; + yield [self::buildEntityWorkflow([$user = new User()]), 'transition3', $user, true, '5b6b95e0-704d-11ef-a5a9-4b6fc11a8eeb']; } public static function provideValidTransition(): iterable { - yield [self::buildEntityWorkflow([$u = new User()]), 'transition1', $u, 'step1']; - yield [self::buildEntityWorkflow([$u = new User()]), 'transition2', $u, 'step2']; - yield [self::buildEntityWorkflow([new User()]), 'transition2', null, 'step2']; - yield [self::buildEntityWorkflow([]), 'transition2', null, 'step2']; - yield [self::buildEntityWorkflow([new User()]), 'transition3', null, 'step3']; - yield [self::buildEntityWorkflow([]), 'transition3', null, 'step3']; + yield [self::buildEntityWorkflow([$u = new User()]), 'transition1', $u, false, 'step1']; + yield [self::buildEntityWorkflow([$u = new User()]), 'transition2', $u, false, 'step2']; + yield [self::buildEntityWorkflow([new User()]), 'transition2', null, false, 'step2']; + yield [self::buildEntityWorkflow([]), 'transition2', null, false, 'step2']; + yield [self::buildEntityWorkflow([new User()]), 'transition3', null, false, 'step3']; + yield [self::buildEntityWorkflow([]), 'transition3', null, false, 'step3']; + + // transition allowed thanks to permission "apply all transitions" + yield [self::buildEntityWorkflow([new User()]), 'transition1', new User(), true, 'step1']; + yield [self::buildEntityWorkflow([new User()]), 'transition2', new User(), true, 'step2']; } public static function buildEntityWorkflow(array $futureDestUsers): EntityWorkflow diff --git a/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/EntityWorkflowGuardTransition.php b/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/EntityWorkflowGuardTransition.php index 25ed21e98..1c9d26fc7 100644 --- a/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/EntityWorkflowGuardTransition.php +++ b/src/Bundle/ChillMainBundle/Workflow/EventSubscriber/EntityWorkflowGuardTransition.php @@ -13,12 +13,24 @@ namespace Chill\MainBundle\Workflow\EventSubscriber; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Workflow\EntityWorkflow; +use Chill\MainBundle\Security\Authorization\EntityWorkflowTransitionVoter; use Chill\MainBundle\Templating\Entity\UserRender; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Security\Core\Security; use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\TransitionBlocker; +/** + * Prevent apply a transition on an entity workflow. + * + * This apply logic and rules to decide if a transition can be applyed. + * + * Those rules are: + * + * - if the transition is system-only or is allowed for user; + * - if the user is present in the dest users for a workflow; + * - or if the user have permission to apply all the transitions + */ class EntityWorkflowGuardTransition implements EventSubscriberInterface { public function __construct( @@ -85,11 +97,17 @@ class EntityWorkflowGuardTransition implements EventSubscriberInterface ); } - if (!$entityWorkflow->getCurrentStep()->getAllDestUser()->contains($user)) { + if ( + !$entityWorkflow->getCurrentStep()->getAllDestUser()->contains($user) + ) { if ($event->getMarking()->has('initial')) { return; } + if ($this->security->isGranted(EntityWorkflowTransitionVoter::APPLY_ALL_TRANSITIONS, $entityWorkflow->getCurrentStep())) { + return; + } + $event->addTransitionBlocker(new TransitionBlocker( 'workflow.You are not allowed to apply a transition on this workflow. Only those users are allowed: %users%', 'f3eeb57c-7532-11ec-9495-e7942a2ac7bc',