From c99dda012679ad8e7f6a8de3eb13430eb7cafde1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 13 Nov 2024 22:41:23 +0100 Subject: [PATCH] Rename WorkflowStoredObjectPermissionHelper to WorkflowRelatedEntityPermissionHelper and create method isAllowedByWorkflow Refactored class names and namespaces from WorkflowStoredObjectPermissionHelper to WorkflowRelatedEntityPermissionHelper across various modules. Updated associated tests and voter classes to reflect the changes, ensuring consistency and clarity in the codebase. --- .../ActivityStoredObjectVoter.php | 4 +- .../AbstractStoredObjectVoter.php | 4 +- ...panyingCourseDocumentStoredObjectVoter.php | 4 +- .../PersonDocumentStoredObjectVoter.php | 4 +- .../AbstractStoredObjectVoterTest.php | 10 +-- .../Authorization/EventStoredObjectVoter.php | 4 +- ...flowRelatedEntityPermissionHelperTest.php} | 71 +++++++++++++++++-- ...WorkflowRelatedEntityPermissionHelper.php} | 36 +++++++++- ...orkEvaluationDocumentStoredObjectVoter.php | 4 +- 9 files changed, 117 insertions(+), 24 deletions(-) rename src/Bundle/{ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php => ChillMainBundle/Tests/Workflow/Helper/WorkflowRelatedEntityPermissionHelperTest.php} (68%) rename src/Bundle/{ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php => ChillMainBundle/Workflow/Helper/WorkflowRelatedEntityPermissionHelper.php} (65%) diff --git a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStoredObjectVoter.php b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStoredObjectVoter.php index 78def7318..6a2a27140 100644 --- a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStoredObjectVoter.php +++ b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStoredObjectVoter.php @@ -16,7 +16,7 @@ use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface; use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter; -use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper; +use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper; use Symfony\Component\Security\Core\Security; class ActivityStoredObjectVoter extends AbstractStoredObjectVoter @@ -24,7 +24,7 @@ class ActivityStoredObjectVoter extends AbstractStoredObjectVoter public function __construct( private readonly ActivityRepository $repository, Security $security, - WorkflowStoredObjectPermissionHelper $workflowDocumentService, + WorkflowRelatedEntityPermissionHelper $workflowDocumentService, ) { parent::__construct($security, $workflowDocumentService); } diff --git a/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/AbstractStoredObjectVoter.php b/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/AbstractStoredObjectVoter.php index 9d77211c2..1b9378e72 100644 --- a/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/AbstractStoredObjectVoter.php +++ b/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/AbstractStoredObjectVoter.php @@ -15,7 +15,7 @@ use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface; use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoterInterface; -use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper; +use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Security; @@ -34,7 +34,7 @@ abstract class AbstractStoredObjectVoter implements StoredObjectVoterInterface public function __construct( private readonly Security $security, - private readonly ?WorkflowStoredObjectPermissionHelper $workflowDocumentService = null, + private readonly ?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null, ) {} public function supports(StoredObjectRoleEnum $attribute, StoredObject $subject): bool diff --git a/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/AccompanyingCourseDocumentStoredObjectVoter.php b/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/AccompanyingCourseDocumentStoredObjectVoter.php index 94ff9149d..e1a9add7d 100644 --- a/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/AccompanyingCourseDocumentStoredObjectVoter.php +++ b/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/AccompanyingCourseDocumentStoredObjectVoter.php @@ -16,7 +16,7 @@ use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository; use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface; use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter; use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; -use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper; +use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper; use Symfony\Component\Security\Core\Security; final class AccompanyingCourseDocumentStoredObjectVoter extends AbstractStoredObjectVoter @@ -24,7 +24,7 @@ final class AccompanyingCourseDocumentStoredObjectVoter extends AbstractStoredOb public function __construct( private readonly AccompanyingCourseDocumentRepository $repository, Security $security, - WorkflowStoredObjectPermissionHelper $workflowDocumentService, + WorkflowRelatedEntityPermissionHelper $workflowDocumentService, ) { parent::__construct($security, $workflowDocumentService); } diff --git a/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/PersonDocumentStoredObjectVoter.php b/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/PersonDocumentStoredObjectVoter.php index 4c8ae693e..16833c535 100644 --- a/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/PersonDocumentStoredObjectVoter.php +++ b/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter/PersonDocumentStoredObjectVoter.php @@ -16,7 +16,7 @@ use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface; use Chill\DocStoreBundle\Repository\PersonDocumentRepository; use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; -use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper; +use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper; use Symfony\Component\Security\Core\Security; class PersonDocumentStoredObjectVoter extends AbstractStoredObjectVoter @@ -24,7 +24,7 @@ class PersonDocumentStoredObjectVoter extends AbstractStoredObjectVoter public function __construct( private readonly PersonDocumentRepository $repository, Security $security, - WorkflowStoredObjectPermissionHelper $workflowDocumentService, + WorkflowRelatedEntityPermissionHelper $workflowDocumentService, ) { parent::__construct($security, $workflowDocumentService); } diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Security/Authorization/AbstractStoredObjectVoterTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Security/Authorization/AbstractStoredObjectVoterTest.php index a045a1fd6..6fbb9c2e4 100644 --- a/src/Bundle/ChillDocStoreBundle/Tests/Security/Authorization/AbstractStoredObjectVoterTest.php +++ b/src/Bundle/ChillDocStoreBundle/Tests/Security/Authorization/AbstractStoredObjectVoterTest.php @@ -15,7 +15,7 @@ use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface; use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter; -use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper; +use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper; use Chill\MainBundle\Entity\User; use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -30,16 +30,16 @@ class AbstractStoredObjectVoterTest extends TestCase { private AssociatedEntityToStoredObjectInterface $repository; private Security $security; - private WorkflowStoredObjectPermissionHelper $workflowDocumentService; + private WorkflowRelatedEntityPermissionHelper $workflowDocumentService; protected function setUp(): void { $this->repository = $this->createMock(AssociatedEntityToStoredObjectInterface::class); $this->security = $this->createMock(Security::class); - $this->workflowDocumentService = $this->createMock(WorkflowStoredObjectPermissionHelper::class); + $this->workflowDocumentService = $this->createMock(WorkflowRelatedEntityPermissionHelper::class); } - private function buildStoredObjectVoter(bool $canBeAssociatedWithWorkflow, AssociatedEntityToStoredObjectInterface $repository, Security $security, ?WorkflowStoredObjectPermissionHelper $workflowDocumentService = null): AbstractStoredObjectVoter + private function buildStoredObjectVoter(bool $canBeAssociatedWithWorkflow, AssociatedEntityToStoredObjectInterface $repository, Security $security, ?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null): AbstractStoredObjectVoter { // Anonymous class extending the abstract class return new class ($canBeAssociatedWithWorkflow, $repository, $security, $workflowDocumentService) extends AbstractStoredObjectVoter { @@ -47,7 +47,7 @@ class AbstractStoredObjectVoterTest extends TestCase private readonly bool $canBeAssociatedWithWorkflow, private readonly AssociatedEntityToStoredObjectInterface $repository, Security $security, - ?WorkflowStoredObjectPermissionHelper $workflowDocumentService = null, + ?WorkflowRelatedEntityPermissionHelper $workflowDocumentService = null, ) { parent::__construct($security, $workflowDocumentService); } diff --git a/src/Bundle/ChillEventBundle/Security/Authorization/EventStoredObjectVoter.php b/src/Bundle/ChillEventBundle/Security/Authorization/EventStoredObjectVoter.php index 9a23d6d85..7e61db7d6 100644 --- a/src/Bundle/ChillEventBundle/Security/Authorization/EventStoredObjectVoter.php +++ b/src/Bundle/ChillEventBundle/Security/Authorization/EventStoredObjectVoter.php @@ -14,7 +14,7 @@ namespace Chill\EventBundle\Security\Authorization; use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface; use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter; -use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper; +use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper; use Chill\EventBundle\Entity\Event; use Chill\EventBundle\Repository\EventRepository; use Chill\EventBundle\Security\EventVoter; @@ -25,7 +25,7 @@ class EventStoredObjectVoter extends AbstractStoredObjectVoter public function __construct( private readonly EventRepository $repository, Security $security, - WorkflowStoredObjectPermissionHelper $workflowDocumentService, + WorkflowRelatedEntityPermissionHelper $workflowDocumentService, ) { parent::__construct($security, $workflowDocumentService); } diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php b/src/Bundle/ChillMainBundle/Tests/Workflow/Helper/WorkflowRelatedEntityPermissionHelperTest.php similarity index 68% rename from src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php rename to src/Bundle/ChillMainBundle/Tests/Workflow/Helper/WorkflowRelatedEntityPermissionHelperTest.php index 9cfd55c57..3e4857d57 100644 --- a/src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Workflow/Helper/WorkflowRelatedEntityPermissionHelperTest.php @@ -9,9 +9,9 @@ declare(strict_types=1); * the LICENSE file that was distributed with this source code. */ -namespace Chill\DocStoreBundle\Tests\Service; +namespace Chill\MainBundle\Tests\Workflow\Helper; -use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper; +use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Workflow\EntityWorkflow; use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum; @@ -36,7 +36,7 @@ use Symfony\Component\Workflow\WorkflowInterface; * * @coversNothing */ -class WorkflowStoredObjectPermissionHelperTest extends TestCase +class WorkflowRelatedEntityPermissionHelperTest extends TestCase { use ProphecyTrait; @@ -53,6 +53,19 @@ class WorkflowStoredObjectPermissionHelperTest extends TestCase self::assertEquals($expected, $helper->notBlockedByWorkflow($entityWorkflow), $message); } + /** + * @dataProvider provideDataAllowedByWorkflow + */ + public function testAllowedByWorkflow(EntityWorkflow $entityWorkflow, User $user, bool $expected, string $message): void + { + // all entities must have this workflow name, so we are ok to set it here + $entityWorkflow->setWorkflowName('dummy'); + $object = new \stdClass(); + $helper = $this->buildHelper($object, $entityWorkflow, $user); + + self::assertEquals($expected, $helper->isAllowedByWorkflow($entityWorkflow), $message); + } + public function testNoWorkflow(): void { $object = new \stdClass(); @@ -60,7 +73,7 @@ class WorkflowStoredObjectPermissionHelperTest extends TestCase self::assertTrue($helper->notBlockedByWorkflow($object), "the user is not blocked by the user, as there aren't any user inside"); } - private function buildHelper(object $relatedEntity, ?EntityWorkflow $entityWorkflow, User $user): WorkflowStoredObjectPermissionHelper + private function buildHelper(object $relatedEntity, ?EntityWorkflow $entityWorkflow, User $user): WorkflowRelatedEntityPermissionHelper { $security = $this->prophesize(Security::class); $security->getUser()->willReturn($user); @@ -72,7 +85,55 @@ class WorkflowStoredObjectPermissionHelperTest extends TestCase $entityWorkflowManager->findByRelatedEntity(Argument::type('object'))->willReturn([]); } - return new WorkflowStoredObjectPermissionHelper($security->reveal(), $entityWorkflowManager->reveal(), $this->buildRegistry()); + return new WorkflowRelatedEntityPermissionHelper($security->reveal(), $entityWorkflowManager->reveal(), $this->buildRegistry()); + } + + public static function provideDataAllowedByWorkflow(): iterable + { + $entityWorkflow = new EntityWorkflow(); + $dto = new WorkflowTransitionContextDTO($entityWorkflow); + $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User()); + + yield [$entityWorkflow, new User(), false, 'not allowed because the user is not present as a dest user']; + + $entityWorkflow = new EntityWorkflow(); + $dto = new WorkflowTransitionContextDTO($entityWorkflow); + $dto->futureDestUsers[] = $user = new User(); + $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User()); + + yield [$entityWorkflow, $user, true, 'allowed because the user is a current user']; + + $entityWorkflow = new EntityWorkflow(); + $dto = new WorkflowTransitionContextDTO($entityWorkflow); + $dto->futureDestUsers[] = $user = new User(); + $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User()); + + $dto = new WorkflowTransitionContextDTO($entityWorkflow); + $dto->futureDestUsers[] = new User(); + $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User()); + + yield [$entityWorkflow, $user, true, 'allowed because the user was a previous user']; + + $entityWorkflow = new EntityWorkflow(); + $dto = new WorkflowTransitionContextDTO($entityWorkflow); + $dto->futureDestUsers[] = $user = new User(); + $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), new User()); + $dto = new WorkflowTransitionContextDTO($entityWorkflow); + $entityWorkflow->setStep('final_positive', $dto, 'to_final_positive', new \DateTimeImmutable(), new User()); + $entityWorkflow->getCurrentStep()->setIsFinal(true); + + yield [$entityWorkflow, $user, false, 'not allowed because: user was a previous user, but it is finalized positive']; + + $entityWorkflow = new EntityWorkflow(); + $dto = new WorkflowTransitionContextDTO($entityWorkflow); + $dto->futureDestUsers[] = $user = new User(); + $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable()); + $dto = new WorkflowTransitionContextDTO($entityWorkflow); + $entityWorkflow->setStep('final_negative', $dto, 'to_final_negative', new \DateTimeImmutable()); + $entityWorkflow->getCurrentStep()->setIsFinal(true); + + yield [$entityWorkflow, $user, true, 'allowed: user was a previous user, it is finalized, but finalized negative']; + } public static function provideDataNotBlockByWorkflow(): iterable diff --git a/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php b/src/Bundle/ChillMainBundle/Workflow/Helper/WorkflowRelatedEntityPermissionHelper.php similarity index 65% rename from src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php rename to src/Bundle/ChillMainBundle/Workflow/Helper/WorkflowRelatedEntityPermissionHelper.php index 95cc77194..472ab93ee 100644 --- a/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php +++ b/src/Bundle/ChillMainBundle/Workflow/Helper/WorkflowRelatedEntityPermissionHelper.php @@ -9,7 +9,7 @@ declare(strict_types=1); * the LICENSE file that was distributed with this source code. */ -namespace Chill\DocStoreBundle\Service; +namespace Chill\MainBundle\Workflow\Helper; use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum; use Chill\MainBundle\Workflow\EntityWorkflowManager; @@ -19,7 +19,7 @@ use Symfony\Component\Workflow\Registry; /** * Check if an object, associated with a workflow, is blocked, or not, by this workflow. */ -class WorkflowStoredObjectPermissionHelper +class WorkflowRelatedEntityPermissionHelper { public function __construct( private readonly Security $security, @@ -27,6 +27,38 @@ class WorkflowStoredObjectPermissionHelper private readonly Registry $registry, ) {} + public function isAllowedByWorkflow(object $entity): bool + { + $entityWorkflows = $this->entityWorkflowManager->findByRelatedEntity($entity); + $currentUser = $this->security->getUser(); + + foreach ($entityWorkflows as $entityWorkflow) { + // if the user is finalized, we have to check if the workflow is finalPositive, or not + if ($entityWorkflow->isFinal()) { + $workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName()); + $marking = $workflow->getMarkingStore()->getMarking($entityWorkflow); + foreach ($marking->getPlaces() as $place => $int) { + $placeMetadata = $workflow->getMetadataStore()->getPlaceMetadata($place); + if (true === ($placeMetadata['isFinalPositive'] ?? false)) { + // the workflow is final, and final positive, so we stop here. + return false; + } + } + } + } + + foreach ($entityWorkflows as $entityWorkflow) { + // so, the workflow is running... We return true if the current user is involved + foreach ($entityWorkflow->getSteps() as $step) { + if ($step->getAllDestUser()->contains($currentUser)) { + return true; + } + } + } + + return false; + } + /** * Return true if the user is allowed to update the given object. * diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/StoredObjectVoter/AccompanyingPeriodWorkEvaluationDocumentStoredObjectVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/StoredObjectVoter/AccompanyingPeriodWorkEvaluationDocumentStoredObjectVoter.php index e2ede26e5..4137cb077 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/StoredObjectVoter/AccompanyingPeriodWorkEvaluationDocumentStoredObjectVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/StoredObjectVoter/AccompanyingPeriodWorkEvaluationDocumentStoredObjectVoter.php @@ -14,7 +14,7 @@ namespace Chill\PersonBundle\Security\Authorization\StoredObjectVoter; use Chill\DocStoreBundle\Repository\AssociatedEntityToStoredObjectInterface; use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter\AbstractStoredObjectVoter; -use Chill\DocStoreBundle\Service\WorkflowStoredObjectPermissionHelper; +use Chill\MainBundle\Workflow\Helper\WorkflowRelatedEntityPermissionHelper; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument; use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocumentRepository; use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkEvaluationDocumentVoter; @@ -25,7 +25,7 @@ class AccompanyingPeriodWorkEvaluationDocumentStoredObjectVoter extends Abstract public function __construct( private readonly AccompanyingPeriodWorkEvaluationDocumentRepository $repository, Security $security, - WorkflowStoredObjectPermissionHelper $workflowDocumentService, + WorkflowRelatedEntityPermissionHelper $workflowDocumentService, ) { parent::__construct($security, $workflowDocumentService); }