mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-29 19:13:49 +00:00
Merge remote-tracking branch 'origin/master' into signature-app-master
This commit is contained in:
@@ -11,29 +11,100 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Workflow\Helper;
|
||||
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum;
|
||||
use Chill\MainBundle\Workflow\EntityWorkflowManager;
|
||||
use Symfony\Component\Clock\ClockInterface;
|
||||
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.
|
||||
* Helper to give supplementary permissions to a related entity.
|
||||
*
|
||||
* If a related entity is associated within a workflow, the logic of the workflow can give more permissions, or
|
||||
* remove some permissions.
|
||||
*
|
||||
* The methods of this helper return either:
|
||||
*
|
||||
* - FORCE_GRANT, which means that a permission can be given, even if it would be denied when the related
|
||||
* entity is not associated with a workflow;
|
||||
* - FORCE_DENIED, which means that a permission should be denied, even if it would be granted when the related entity
|
||||
* is not associated with a workflow
|
||||
* - ABSTAIN, if there is no workflow logic to add or remove permission
|
||||
*
|
||||
* For read operations:
|
||||
*
|
||||
* - if the user is involved in the workflow (is part of the current step, of a step before), the user is granted read
|
||||
* operation;
|
||||
* - if there is a pending signature for a person, the workflow grant access to the related entity;
|
||||
* - if there a signature applyied in less than 12 hours, the workflow grant access to the related entity. This allow to
|
||||
* show the related entity to the person during this time frame.
|
||||
*
|
||||
*
|
||||
* For write operation:
|
||||
*
|
||||
* - if the workflow is finalized "positive" (means "not canceled"), the workflow denys write operations;
|
||||
* - if there isn't any finalized "positive" workflow, and if there is a signature appliyed for a running workflow (not finalized nor canceled),
|
||||
* the workflow denys write operations;
|
||||
* - if there is no case above and the user is involved in the workflow (is part of the current step, of a step before), the user is granted;
|
||||
*/
|
||||
class WorkflowRelatedEntityPermissionHelper
|
||||
{
|
||||
public const FORCE_GRANT = 'FORCE_GRANT';
|
||||
public const FORCE_DENIED = 'FORCE_DENIED';
|
||||
public const ABSTAIN = 'ABSTAIN';
|
||||
|
||||
public function __construct(
|
||||
private readonly Security $security,
|
||||
private readonly EntityWorkflowManager $entityWorkflowManager,
|
||||
private readonly Registry $registry,
|
||||
private readonly ClockInterface $clock,
|
||||
) {}
|
||||
|
||||
public function isAllowedByWorkflow(object $entity): bool
|
||||
/**
|
||||
* @return 'FORCE_GRANT'|'FORCE_DENIED'|'ABSTAIN'
|
||||
*/
|
||||
public function isAllowedByWorkflowForReadOperation(object $entity): string
|
||||
{
|
||||
$entityWorkflows = $this->entityWorkflowManager->findByRelatedEntity($entity);
|
||||
$currentUser = $this->security->getUser();
|
||||
|
||||
if ($this->isUserInvolvedInAWorkflow($entityWorkflows)) {
|
||||
return self::FORCE_GRANT;
|
||||
}
|
||||
|
||||
// give a view permission if there is a Person signature pending, or in the 12 hours following
|
||||
// the signature last state
|
||||
foreach ($entityWorkflows as $workflow) {
|
||||
foreach ($workflow->getCurrentStep()->getSignatures() as $signature) {
|
||||
if ('person' === $signature->getSignerKind()) {
|
||||
if (EntityWorkflowSignatureStateEnum::PENDING === $signature->getState()) {
|
||||
return self::FORCE_GRANT;
|
||||
}
|
||||
$signatureDate = $signature->getStateDate();
|
||||
$visibleUntil = $signatureDate->add(new \DateInterval('PT12H'));
|
||||
|
||||
if ($visibleUntil > $this->clock->now()) {
|
||||
return self::FORCE_GRANT;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self::ABSTAIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 'FORCE_GRANT'|'FORCE_DENIED'|'ABSTAIN'
|
||||
*/
|
||||
public function isAllowedByWorkflowForWriteOperation(object $entity): string
|
||||
{
|
||||
$entityWorkflows = $this->entityWorkflowManager->findByRelatedEntity($entity);
|
||||
$runningWorkflows = [];
|
||||
|
||||
// if a workflow is finalized positive, we are not allowed to edit to document any more
|
||||
|
||||
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);
|
||||
@@ -41,12 +112,40 @@ class WorkflowRelatedEntityPermissionHelper
|
||||
$placeMetadata = $workflow->getMetadataStore()->getPlaceMetadata($place);
|
||||
if (true === ($placeMetadata['isFinalPositive'] ?? false)) {
|
||||
// the workflow is final, and final positive, so we stop here.
|
||||
return false;
|
||||
return self::FORCE_DENIED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$runningWorkflows[] = $entityWorkflow;
|
||||
}
|
||||
}
|
||||
|
||||
// if there is a signature on a **running workflow**, no one can edit the workflow any more
|
||||
foreach ($runningWorkflows as $entityWorkflow) {
|
||||
foreach ($entityWorkflow->getSteps() as $step) {
|
||||
foreach ($step->getSignatures() as $signature) {
|
||||
if (EntityWorkflowSignatureStateEnum::SIGNED === $signature->getState()) {
|
||||
return self::FORCE_DENIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// allow only the users involved
|
||||
if ($this->isUserInvolvedInAWorkflow($runningWorkflows)) {
|
||||
return self::FORCE_GRANT;
|
||||
}
|
||||
|
||||
return self::ABSTAIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<EntityWorkflow> $entityWorkflows
|
||||
*/
|
||||
private function isUserInvolvedInAWorkflow(array $entityWorkflows): bool
|
||||
{
|
||||
$currentUser = $this->security->getUser();
|
||||
|
||||
foreach ($entityWorkflows as $entityWorkflow) {
|
||||
// so, the workflow is running... We return true if the current user is involved
|
||||
foreach ($entityWorkflow->getSteps() as $step) {
|
||||
@@ -58,58 +157,4 @@ class WorkflowRelatedEntityPermissionHelper
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
// as soon as there is one signatured applyied, we are not able to
|
||||
// edit the document any more
|
||||
foreach ($entityWorkflow->getSteps() as $step) {
|
||||
foreach ($step->getSignatures() as $signature) {
|
||||
if (EntityWorkflowSignatureStateEnum::SIGNED === $signature->getState()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user