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.
This commit is contained in:
Julien Fastré 2024-11-13 22:41:23 +01:00
parent d50b169ab8
commit c99dda0126
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
9 changed files with 117 additions and 24 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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.
*

View File

@ -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);
}