From 64d91e2afe5161bb9bf734d01982401e043665e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 8 Nov 2024 20:34:45 +0100 Subject: [PATCH] Allow users to edit a document if they were added to the previous step of a workflow. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OP#826 Workflow - les utilisateurs des étapes précédentes sur un workflow doivent aussi avoir la main sur les étapes en cours du workflow (Vendee/accent-suivi-developpement/1289) https://champs-libres.openproject.com/work_packages/826 --- .../WorkflowStoredObjectPermissionHelper.php | 53 +++++++++++++------ ...rkflowStoredObjectPermissionHelperTest.php | 25 ++++++++- .../Entity/Workflow/EntityWorkflow.php | 3 ++ 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php b/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php index 971371bea..95cc77194 100644 --- a/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php +++ b/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php @@ -16,6 +16,9 @@ use Chill\MainBundle\Workflow\EntityWorkflowManager; use Symfony\Component\Security\Core\Security; use Symfony\Component\Workflow\Registry; +/** + * Check if an object, associated with a workflow, is blocked, or not, by this workflow. + */ class WorkflowStoredObjectPermissionHelper { public function __construct( @@ -24,28 +27,19 @@ class WorkflowStoredObjectPermissionHelper private readonly Registry $registry, ) {} + /** + * Return true if the user is allowed to update the given object. + * + * Return false if some workflow block the edition of the object. + */ public function notBlockedByWorkflow(object $entity): bool { $entityWorkflows = $this->entityWorkflowManager->findByRelatedEntity($entity); $currentUser = $this->security->getUser(); + $usersInvolved = []; + $entityWorkflowsNotFinalizedPositive = []; foreach ($entityWorkflows as $entityWorkflow) { - if ($entityWorkflow->isFinal()) { - - $workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName()); - $marking = $workflow->getMarkingStore()->getMarking($entityWorkflow); - foreach ($marking->getPlaces() as $place => $active) { - $metadata = $workflow->getMetadataStore()->getPlaceMetadata($place); - if ($metadata['isFinalPositive'] ?? true) { - return false; - } - } - } else { - if (!$entityWorkflow->getCurrentStep()->getAllDestUser()->contains($currentUser)) { - return false; - } - } - // as soon as there is one signatured applyied, we are not able to // edit the document any more foreach ($entityWorkflow->getSteps() as $step) { @@ -55,6 +49,33 @@ class WorkflowStoredObjectPermissionHelper } } } + + if ($entityWorkflow->isFinal()) { + $workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName()); + $marking = $workflow->getMarkingStore()->getMarking($entityWorkflow); + foreach ($marking->getPlaces() as $place => $active) { + $metadata = $workflow->getMetadataStore()->getPlaceMetadata($place); + if ($metadata['isFinalPositive'] ?? true) { + return false; + } + } + } else { + $entityWorkflowsNotFinalizedPositive[] = $entityWorkflow; + foreach ($entityWorkflow->getSteps() as $step) { + foreach ($step->getAllDestUser()->toArray() as $user) { + $usersInvolved[] = $user; + } + } + } + } + + // if there isn't any user, but a workflow, blocked + if ([] !== $entityWorkflowsNotFinalizedPositive) { + if ([] === $usersInvolved) { + return false; + } + + return in_array($currentUser, $usersInvolved, true); } return true; diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php index 8f693f44e..9cfd55c57 100644 --- a/src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php +++ b/src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php @@ -53,13 +53,24 @@ class WorkflowStoredObjectPermissionHelperTest extends TestCase self::assertEquals($expected, $helper->notBlockedByWorkflow($entityWorkflow), $message); } - private function buildHelper(object $relatedEntity, EntityWorkflow $entityWorkflow, User $user): WorkflowStoredObjectPermissionHelper + public function testNoWorkflow(): void + { + $object = new \stdClass(); + $helper = $this->buildHelper($object, null, $user = new User()); + 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 { $security = $this->prophesize(Security::class); $security->getUser()->willReturn($user); $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class); - $entityWorkflowManager->findByRelatedEntity(Argument::type('object'))->willReturn([$entityWorkflow]); + if (null !== $entityWorkflow) { + $entityWorkflowManager->findByRelatedEntity(Argument::type('object'))->willReturn([$entityWorkflow]); + } else { + $entityWorkflowManager->findByRelatedEntity(Argument::type('object'))->willReturn([]); + } return new WorkflowStoredObjectPermissionHelper($security->reveal(), $entityWorkflowManager->reveal(), $this->buildRegistry()); } @@ -79,6 +90,16 @@ class WorkflowStoredObjectPermissionHelperTest extends TestCase yield [$entityWorkflow, $user, true, 'allowed because the user is 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(), $user); + $dto = new WorkflowTransitionContextDTO($entityWorkflow); + $dto->futureDestUsers[] = new User(); + $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), $user); + + yield [$entityWorkflow, $user, true, 'allowed because the user is present as a **previous** dest user']; + $entityWorkflow = new EntityWorkflow(); $dto = new WorkflowTransitionContextDTO($entityWorkflow); $dto->futureDestUsers[] = $user = new User(); diff --git a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php index d67a04b4b..99d5cdb7d 100644 --- a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php +++ b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php @@ -243,6 +243,9 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface throw new \RuntimeException(); } + /** + * @return Selectable&Collection + */ public function getSteps(): Collection&Selectable { return $this->steps;