Allow users to edit a document if they were added to the previous step of a workflow.

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
This commit is contained in:
Julien Fastré 2024-11-08 20:34:45 +01:00
parent 5339d4f5d9
commit 64d91e2afe
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
3 changed files with 63 additions and 18 deletions

View File

@ -16,6 +16,9 @@ use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Security;
use Symfony\Component\Workflow\Registry; use Symfony\Component\Workflow\Registry;
/**
* Check if an object, associated with a workflow, is blocked, or not, by this workflow.
*/
class WorkflowStoredObjectPermissionHelper class WorkflowStoredObjectPermissionHelper
{ {
public function __construct( public function __construct(
@ -24,28 +27,19 @@ class WorkflowStoredObjectPermissionHelper
private readonly Registry $registry, 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 public function notBlockedByWorkflow(object $entity): bool
{ {
$entityWorkflows = $this->entityWorkflowManager->findByRelatedEntity($entity); $entityWorkflows = $this->entityWorkflowManager->findByRelatedEntity($entity);
$currentUser = $this->security->getUser(); $currentUser = $this->security->getUser();
$usersInvolved = [];
$entityWorkflowsNotFinalizedPositive = [];
foreach ($entityWorkflows as $entityWorkflow) { 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 // as soon as there is one signatured applyied, we are not able to
// edit the document any more // edit the document any more
foreach ($entityWorkflow->getSteps() as $step) { 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; return true;

View File

@ -53,13 +53,24 @@ class WorkflowStoredObjectPermissionHelperTest extends TestCase
self::assertEquals($expected, $helper->notBlockedByWorkflow($entityWorkflow), $message); 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 = $this->prophesize(Security::class);
$security->getUser()->willReturn($user); $security->getUser()->willReturn($user);
$entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class); $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()); 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']; 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(); $entityWorkflow = new EntityWorkflow();
$dto = new WorkflowTransitionContextDTO($entityWorkflow); $dto = new WorkflowTransitionContextDTO($entityWorkflow);
$dto->futureDestUsers[] = $user = new User(); $dto->futureDestUsers[] = $user = new User();

View File

@ -243,6 +243,9 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
throw new \RuntimeException(); throw new \RuntimeException();
} }
/**
* @return Selectable<int, EntityWorkflowStep>&Collection<int, EntityWorkflowStep>
*/
public function getSteps(): Collection&Selectable public function getSteps(): Collection&Selectable
{ {
return $this->steps; return $this->steps;