From 73797b98f670c20535b8f1ca03a5f7de5862d224 Mon Sep 17 00:00:00 2001 From: Julie Lenaerts Date: Thu, 20 Jun 2024 17:32:09 +0200 Subject: [PATCH] Add WorkflowDocumentService and use in StoredObject voters A WorkflowDocumentService was created that can be injected\ in context-specific StoredObject voters that need to check whether\ the document in question is attached to a workflow. --- ...panyingCourseDocumentStoredObjectVoter.php | 31 ++++++++++------ .../Service/WorkflowDocumentService.php | 35 +++++++++++++++++++ 2 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 src/Bundle/ChillDocStoreBundle/Service/WorkflowDocumentService.php diff --git a/src/Bundle/ChillDocStoreBundle/Security/Authorization/AccompanyingCourseDocumentStoredObjectVoter.php b/src/Bundle/ChillDocStoreBundle/Security/Authorization/AccompanyingCourseDocumentStoredObjectVoter.php index db1499a99..931378a61 100644 --- a/src/Bundle/ChillDocStoreBundle/Security/Authorization/AccompanyingCourseDocumentStoredObjectVoter.php +++ b/src/Bundle/ChillDocStoreBundle/Security/Authorization/AccompanyingCourseDocumentStoredObjectVoter.php @@ -2,13 +2,15 @@ namespace ChillDocStoreBundle\Security\Authorization; +use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument; use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository; use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter; use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoterInterface; +use Chill\DocStoreBundle\Service\WorkflowDocumentService; use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Entity\Workflow\EntityWorkflow; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Security; class AccompanyingCourseDocumentStoredObjectVoter implements StoredObjectVoterInterface { @@ -16,15 +18,15 @@ class AccompanyingCourseDocumentStoredObjectVoter implements StoredObjectVoterIn public function __construct( private readonly AccompanyingCourseDocumentRepository $repository, - private readonly Security $security, - private readonly AccompanyingCourseDocumentVoter $accompanyingCourseDocumentVoter + private readonly AccompanyingCourseDocumentVoter $accompanyingCourseDocumentVoter, + private readonly WorkflowDocumentService $workflowDocumentService ){ } public function supports(string $attribute, StoredObject $subject): bool { // check if the stored object is linked to an AccompanyingCourseDocument - return !empty($this->repository->findLinkedCourseDocument($subject->getId())); + return $this->repository->findLinkedCourseDocument($subject) instanceof AccompanyingCourseDocument; } public function voteOnAttribute(string $attribute, StoredObject $subject, TokenInterface $token): bool @@ -34,17 +36,26 @@ class AccompanyingCourseDocumentStoredObjectVoter implements StoredObjectVoterIn } // Retrieve the related accompanying course document - $accompanyingCourseDocument = $this->repository->findLinkedCourseDocument($subject->getId()); + $accompanyingCourseDocument = $this->repository->findLinkedCourseDocument($subject); // Determine the attribute to pass to AccompanyingCourseDocumentVoter - $voterAttribute = ($attribute === self::SEE_AND_EDIT) ? AccompanyingCourseDocumentVoter::UPDATE : AccompanyingCourseDocumentVoter::SEE_DETAILS; + $voterAttribute = match($attribute) { + self::SEE_AND_EDIT => AccompanyingCourseDocumentVoter::UPDATE, + default => AccompanyingCourseDocumentVoter::SEE_DETAILS, + }; // Check access using AccompanyingCourseDocumentVoter - if ($this->accompanyingCourseDocumentVoter->voteOnAttribute($voterAttribute, $accompanyingCourseDocument, $token)) { - // TODO implement logic to check for associated workflow - return true; - } else { + if (false === $this->accompanyingCourseDocumentVoter->voteOnAttribute($voterAttribute, $accompanyingCourseDocument, $token)) { return false; } + + // Check if entity is related to a workflow, if so, check if user can apply transition + $relatedWorkflow = $this->workflowDocumentService->getRelatedWorkflow($accompanyingCourseDocument); + + if ($relatedWorkflow instanceof EntityWorkflow){ + return $this->workflowDocumentService->canApplyTransition($relatedWorkflow); + } + + return true; } } diff --git a/src/Bundle/ChillDocStoreBundle/Service/WorkflowDocumentService.php b/src/Bundle/ChillDocStoreBundle/Service/WorkflowDocumentService.php new file mode 100644 index 000000000..498348b96 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Service/WorkflowDocumentService.php @@ -0,0 +1,35 @@ +repository->findByRelatedEntity(get_class($entity), $entity->getId()); + } + + public function canApplyTransition(EntityWorkflow $entityWorkflow): bool + { + if ($entityWorkflow->isFinal()) { + return false; + } + + $currentUser = $this->security->getUser(); + if ($entityWorkflow->getCurrentStep()->getAllDestUser()->contains($currentUser)) { + return true; + } + + return false; + } + +}