diff --git a/src/Bundle/ChillDocStoreBundle/Controller/SignatureRequestController.php b/src/Bundle/ChillDocStoreBundle/Controller/SignatureRequestController.php index 26fc1b098..c6c564be1 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/SignatureRequestController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/SignatureRequestController.php @@ -18,10 +18,12 @@ use Chill\DocStoreBundle\Service\StoredObjectManagerInterface; use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum; use Chill\MainBundle\Entity\Workflow\EntityWorkflowStepSignature; use Chill\MainBundle\Templating\Entity\ChillEntityRenderManagerInterface; +use Chill\MainBundle\Security\Authorization\EntityWorkflowStepSignatureVoter; use Chill\MainBundle\Workflow\EntityWorkflowManager; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Security; @@ -41,6 +43,10 @@ class SignatureRequestController #[Route('/api/1.0/document/workflow/{id}/signature-request', name: 'chill_docstore_signature_request')] public function processSignature(EntityWorkflowStepSignature $signature, Request $request): JsonResponse { + if (!$this->security->isGranted(EntityWorkflowStepSignatureVoter::SIGN, $signature)) { + throw new AccessDeniedHttpException('not authorized to sign this step'); + } + $entityWorkflow = $signature->getStep()->getEntityWorkflow(); if (EntityWorkflowSignatureStateEnum::PENDING !== $signature->getState()) { diff --git a/src/Bundle/ChillMainBundle/Controller/WorkflowAddSignatureController.php b/src/Bundle/ChillMainBundle/Controller/WorkflowAddSignatureController.php index deb90119b..2aa180b7a 100644 --- a/src/Bundle/ChillMainBundle/Controller/WorkflowAddSignatureController.php +++ b/src/Bundle/ChillMainBundle/Controller/WorkflowAddSignatureController.php @@ -14,13 +14,16 @@ namespace Chill\MainBundle\Controller; use Chill\DocStoreBundle\Service\Signature\PDFSignatureZoneAvailable; use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum; use Chill\MainBundle\Entity\Workflow\EntityWorkflowStepSignature; +use Chill\MainBundle\Security\Authorization\EntityWorkflowStepSignatureVoter; use Chill\MainBundle\Workflow\EntityWorkflowManager; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Twig\Environment; @@ -32,11 +35,16 @@ final readonly class WorkflowAddSignatureController private NormalizerInterface $normalizer, private Environment $twig, private UrlGeneratorInterface $urlGenerator, + private Security $security, ) {} #[Route(path: '/{_locale}/main/workflow/signature/{id}/sign', name: 'chill_main_workflow_signature_add', methods: 'GET')] public function __invoke(EntityWorkflowStepSignature $signature, Request $request): Response { + if (!$this->security->isGranted(EntityWorkflowStepSignatureVoter::SIGN, $signature)) { + throw new AccessDeniedHttpException('not authorized to sign this step'); + } + $entityWorkflow = $signature->getStep()->getEntityWorkflow(); if (EntityWorkflowSignatureStateEnum::PENDING !== $signature->getState()) { diff --git a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php index 08b5ee41f..89efde7c0 100644 --- a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php +++ b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php @@ -318,7 +318,7 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface } } - return $usersInvolved; + return array_values($usersInvolved); } public function getWorkflowName(): string @@ -446,6 +446,10 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface $newStep->addDestUser($user); } + if (null !== $transitionContextDTO->futureUserSignature) { + $newStep->addDestUser($transitionContextDTO->futureUserSignature); + } + foreach ($transitionContextDTO->futureDestEmails as $email) { $newStep->addDestEmail($email); } diff --git a/src/Bundle/ChillMainBundle/Resources/views/Workflow/_signature.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Workflow/_signature.html.twig index 50172089c..b0e401645 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Workflow/_signature.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Workflow/_signature.html.twig @@ -23,14 +23,18 @@ {% if s.isSigned %} {{ 'workflow.signature_zone.has_signed_statement'|trans({ 'datetime' : s.stateDate }) }} {% else %} - + {% if is_granted('CHILL_MAIN_ENTITY_WORKFLOW_SIGNATURE_SIGN', s) %} + + {% else %} + {{ 'workflow.waiting_for_signature'|trans }} + {% endif %} {% endif %} diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/EntityWorkflowStepSignatureVoter.php b/src/Bundle/ChillMainBundle/Security/Authorization/EntityWorkflowStepSignatureVoter.php new file mode 100644 index 000000000..683f1352f --- /dev/null +++ b/src/Bundle/ChillMainBundle/Security/Authorization/EntityWorkflowStepSignatureVoter.php @@ -0,0 +1,41 @@ +getSigner() instanceof Person) { + return true; + } + + if ($subject->getSigner() === $token->getUser()) { + return true; + } + + return false; + } +} diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderManager.php b/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderManager.php index 51315a6d6..daca1fb8a 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderManager.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderManager.php @@ -18,8 +18,8 @@ final readonly class ChillEntityRenderManager implements ChillEntityRenderManage public function __construct(/** * @var iterable */ - private iterable $renders) - { + private iterable $renders, + ) { $this->defaultRender = new ChillEntityRender(); } diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/WorkflowAddSignatureControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/WorkflowAddSignatureControllerTest.php index 4b6fd38e2..9b4507936 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/WorkflowAddSignatureControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/WorkflowAddSignatureControllerTest.php @@ -18,12 +18,14 @@ use Chill\DocStoreBundle\Service\Signature\PDFSignatureZoneAvailable; use Chill\MainBundle\Controller\WorkflowAddSignatureController; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Workflow\EntityWorkflow; +use Chill\MainBundle\Security\Authorization\EntityWorkflowStepSignatureVoter; use Chill\MainBundle\Workflow\EntityWorkflowManager; use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO; use Chill\PersonBundle\Entity\Person; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Twig\Environment; @@ -65,7 +67,11 @@ class WorkflowAddSignatureControllerTest extends TestCase $urlGenerator = $this->createMock(UrlGeneratorInterface::class); - $controller = new WorkflowAddSignatureController($entityWorkflowManager, $pdfSignatureZoneAvailable, $normalizer, $twig, $urlGenerator); + $security = $this->createMock(Security::class); + $security->expects($this->once())->method('isGranted')->with(EntityWorkflowStepSignatureVoter::SIGN, $signature) + ->willReturn(true); + + $controller = new WorkflowAddSignatureController($entityWorkflowManager, $pdfSignatureZoneAvailable, $normalizer, $twig, $urlGenerator, $security); $actual = $controller($signature, new Request()); diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml index 0c0fce51c..003dcbee5 100644 --- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml @@ -531,9 +531,10 @@ workflow: Remove hold: Enlever la mise en attente On hold: En attente Automated transition: Transition automatique + waiting_for_signature: En attente de signature signature_zone: - title: Appliquer les signatures électroniques + title: Signatures électroniques button_sign: Signer metadata: sign_by: 'Signature pour %name%'