From 9b661c3b8f1c41805dc0fd29cd64bcb9301de4e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 14 Nov 2024 08:49:26 +0100 Subject: [PATCH 1/5] Let ConvertController return a pdf file directly without trying to converting it Those changes improve performance when the file is already in pdf format. --- .../src/Controller/ConvertController.php | 10 ++++++++++ .../tests/Controller/ConvertControllerTest.php | 3 +++ 2 files changed, 13 insertions(+) diff --git a/src/Bundle/ChillWopiBundle/src/Controller/ConvertController.php b/src/Bundle/ChillWopiBundle/src/Controller/ConvertController.php index 86a624e4b..3b97dc6fe 100644 --- a/src/Bundle/ChillWopiBundle/src/Controller/ConvertController.php +++ b/src/Bundle/ChillWopiBundle/src/Controller/ConvertController.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\WopiBundle\Controller; use Chill\DocStoreBundle\Entity\StoredObject; +use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; use Chill\DocStoreBundle\Service\StoredObjectManager; use Chill\DocStoreBundle\Service\StoredObjectManagerInterface; use Chill\WopiBundle\Service\WopiConverter; @@ -41,7 +42,16 @@ class ConvertController throw new AccessDeniedHttpException('User must be authenticated'); } + if (!$this->security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)) { + throw new AccessDeniedHttpException('not allowed to see this document'); + } + $content = $this->storedObjectManager->read($storedObject); + + if ('application/pdf' === $storedObject->getType()) { + return new Response($content, Response::HTTP_OK, ['Content-Type' => 'application/pdf']); + } + $lang = $request->getLocale(); try { diff --git a/src/Bundle/ChillWopiBundle/tests/Controller/ConvertControllerTest.php b/src/Bundle/ChillWopiBundle/tests/Controller/ConvertControllerTest.php index 9a529df6b..5f99f0fd2 100644 --- a/src/Bundle/ChillWopiBundle/tests/Controller/ConvertControllerTest.php +++ b/src/Bundle/ChillWopiBundle/tests/Controller/ConvertControllerTest.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\WopiBundle\Tests\Controller; use Chill\DocStoreBundle\Entity\StoredObject; +use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum; use Chill\DocStoreBundle\Service\StoredObjectManagerInterface; use Chill\WopiBundle\Controller\ConvertController; use Chill\WopiBundle\Service\WopiConverter; @@ -37,6 +38,7 @@ final class ConvertControllerTest extends TestCase $security = $this->prophesize(Security::class); $security->isGranted('ROLE_USER')->willReturn(true); + $security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)->willReturn(true); $storeManager = $this->prophesize(StoredObjectManagerInterface::class); $storeManager->read($storedObject)->willReturn('content'); @@ -67,6 +69,7 @@ final class ConvertControllerTest extends TestCase $security = $this->prophesize(Security::class); $security->isGranted('ROLE_USER')->willReturn(true); + $security->isGranted(StoredObjectRoleEnum::SEE->value, $storedObject)->willReturn(true); $storeManager = $this->prophesize(StoredObjectManagerInterface::class); $storeManager->read($storedObject)->willReturn('content'); From 5d5150faa772176a6475a808002c6e5b72e3df5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 15 Nov 2024 14:13:38 +0100 Subject: [PATCH 2/5] Add 'btn-sm' class to download button The 'btn-sm' class was added to the download button in HistoryButtonListItem.vue to adjust its size. Additionally, a bug was fixed in DownloadButton.vue to correctly reference the 'type' property from 'atVersion'. --- .../public/vuejs/StoredObjectButton/DownloadButton.vue | 2 +- .../StoredObjectButton/HistoryButton/HistoryButtonListItem.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/DownloadButton.vue b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/DownloadButton.vue index 0e6da5ef4..f3fd3b4b5 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/DownloadButton.vue +++ b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/DownloadButton.vue @@ -3,7 +3,7 @@ - + diff --git a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/HistoryButton/HistoryButtonListItem.vue b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/HistoryButton/HistoryButtonListItem.vue index 81436ee35..13ad2b547 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/HistoryButton/HistoryButtonListItem.vue +++ b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/HistoryButton/HistoryButtonListItem.vue @@ -55,7 +55,7 @@ const classes = computed<{row: true, 'row-hover': true, 'blinking-1': boolean, '
  • - +
  • From a312b45777080e4e50e1af2494eae7df9c46290f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 15 Nov 2024 14:14:13 +0100 Subject: [PATCH 3/5] Remove ConvertToPdfBeforeSignatureStepEventSubscriber This commit deletes the ConvertToPdfBeforeSignatureStepEventSubscriber.php file from the workflow directory. . --- ...BeforeSignatureStepEventSubscriberTest.php | 208 ------------------ ...oPdfBeforeSignatureStepEventSubscriber.php | 75 ------- 2 files changed, 283 deletions(-) delete mode 100644 src/Bundle/ChillDocStoreBundle/Tests/Workflow/ConvertToPdfBeforeSignatureStepEventSubscriberTest.php delete mode 100644 src/Bundle/ChillDocStoreBundle/Workflow/ConvertToPdfBeforeSignatureStepEventSubscriber.php diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Workflow/ConvertToPdfBeforeSignatureStepEventSubscriberTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Workflow/ConvertToPdfBeforeSignatureStepEventSubscriberTest.php deleted file mode 100644 index 572cb192c..000000000 --- a/src/Bundle/ChillDocStoreBundle/Tests/Workflow/ConvertToPdfBeforeSignatureStepEventSubscriberTest.php +++ /dev/null @@ -1,208 +0,0 @@ -registerVersion(); - - $converter = $this->prophesize(StoredObjectToPdfConverter::class); - $converter->addConvertedVersion($storedObject, 'fr', 'pdf') - ->shouldBeCalledOnce() - ->will(function ($args) { - /** @var StoredObject $storedObject */ - $storedObject = $args[0]; - - $pointInTime = new StoredObjectPointInTime($storedObject->getCurrentVersion(), StoredObjectPointInTimeReasonEnum::KEEP_BEFORE_CONVERSION); - $newVersion = $storedObject->registerVersion(filename: 'next'); - - return [$pointInTime, $newVersion]; - }); - - $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class); - $entityWorkflowManager->getAssociatedStoredObject($entityWorkflow)->willReturn($storedObject); - - $request = new Request(); - $request->setLocale('fr'); - $stack = new RequestStack(); - $stack->push($request); - - $eventSubscriber = new ConvertToPdfBeforeSignatureStepEventSubscriber($entityWorkflowManager->reveal(), $converter->reveal(), $stack); - - $registry = $this->buildRegistry($eventSubscriber); - $workflow = $registry->get($entityWorkflow, 'dummy'); - - $dto = new WorkflowTransitionContextDTO($entityWorkflow); - $workflow->apply($entityWorkflow, 'to_signature', ['context' => $dto, 'transition' => 'to_signature', 'transitionAt' => new \DateTimeImmutable('now')]); - - self::assertEquals('signature', $entityWorkflow->getStep()); - self::assertNotSame($previousVersion, $storedObject->getCurrentVersion()); - self::assertTrue($previousVersion->hasPointInTimes()); - self::assertCount(2, $storedObject->getVersions()); - self::assertEquals('next', $storedObject->getCurrentVersion()->getFilename()); - } - - public function testConvertToPdfBeforeSignatureStepEventSubscriberToNotASignatureStep(): void - { - $entityWorkflow = new EntityWorkflow(); - $storedObject = new StoredObject(); - $previousVersion = $storedObject->registerVersion(); - - $converter = $this->prophesize(StoredObjectToPdfConverter::class); - $converter->addConvertedVersion($storedObject, 'fr', 'pdf') - ->shouldNotBeCalled(); - - $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class); - $entityWorkflowManager->getAssociatedStoredObject($entityWorkflow)->willReturn($storedObject); - - $request = new Request(); - $request->setLocale('fr'); - $stack = new RequestStack(); - $stack->push($request); - - $eventSubscriber = new ConvertToPdfBeforeSignatureStepEventSubscriber($entityWorkflowManager->reveal(), $converter->reveal(), $stack); - - $registry = $this->buildRegistry($eventSubscriber); - $workflow = $registry->get($entityWorkflow, 'dummy'); - - $dto = new WorkflowTransitionContextDTO($entityWorkflow); - $workflow->apply($entityWorkflow, 'to_something', ['context' => $dto, 'transition' => 'to_something', 'transitionAt' => new \DateTimeImmutable('now')]); - - self::assertEquals('something', $entityWorkflow->getStep()); - self::assertSame($previousVersion, $storedObject->getCurrentVersion()); - self::assertFalse($previousVersion->hasPointInTimes()); - self::assertCount(1, $storedObject->getVersions()); - } - - public function testConvertToPdfBeforeSignatureStepEventSubscriberToSignatureAlreadyAPdf(): void - { - $entityWorkflow = new EntityWorkflow(); - $storedObject = new StoredObject(); - $previousVersion = $storedObject->registerVersion(type: 'application/pdf'); - - $converter = $this->prophesize(StoredObjectToPdfConverter::class); - $converter->addConvertedVersion($storedObject, 'fr', 'pdf') - ->shouldNotBeCalled(); - - $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class); - $entityWorkflowManager->getAssociatedStoredObject($entityWorkflow)->willReturn($storedObject); - - $request = new Request(); - $request->setLocale('fr'); - $stack = new RequestStack(); - $stack->push($request); - - $eventSubscriber = new ConvertToPdfBeforeSignatureStepEventSubscriber($entityWorkflowManager->reveal(), $converter->reveal(), $stack); - - $registry = $this->buildRegistry($eventSubscriber); - $workflow = $registry->get($entityWorkflow, 'dummy'); - - $dto = new WorkflowTransitionContextDTO($entityWorkflow); - $workflow->apply($entityWorkflow, 'to_signature', ['context' => $dto, 'transition' => 'to_signature', 'transitionAt' => new \DateTimeImmutable('now')]); - - self::assertEquals('signature', $entityWorkflow->getStep()); - self::assertSame($previousVersion, $storedObject->getCurrentVersion()); - self::assertFalse($previousVersion->hasPointInTimes()); - self::assertCount(1, $storedObject->getVersions()); - } - - public function testConvertToPdfBeforeSignatureStepEventSubscriberToSignatureWithNoStoredObject(): void - { - $entityWorkflow = new EntityWorkflow(); - - $converter = $this->prophesize(StoredObjectToPdfConverter::class); - $converter->addConvertedVersion(Argument::type(StoredObject::class), 'fr', 'pdf') - ->shouldNotBeCalled(); - - $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class); - $entityWorkflowManager->getAssociatedStoredObject($entityWorkflow)->willReturn(null); - - $request = new Request(); - $request->setLocale('fr'); - $stack = new RequestStack(); - $stack->push($request); - - $eventSubscriber = new ConvertToPdfBeforeSignatureStepEventSubscriber($entityWorkflowManager->reveal(), $converter->reveal(), $stack); - - $registry = $this->buildRegistry($eventSubscriber); - $workflow = $registry->get($entityWorkflow, 'dummy'); - - $dto = new WorkflowTransitionContextDTO($entityWorkflow); - $workflow->apply($entityWorkflow, 'to_signature', ['context' => $dto, 'transition' => 'to_signature', 'transitionAt' => new \DateTimeImmutable('now')]); - - self::assertEquals('signature', $entityWorkflow->getStep()); - } - - private function buildRegistry(EventSubscriberInterface $eventSubscriber): Registry - { - $builder = new DefinitionBuilder(); - $builder - ->setInitialPlaces('initial') - ->addPlaces(['initial', 'signature', 'something']) - ->addTransition(new Transition('to_something', 'initial', 'something')) - ->addTransition(new Transition('to_signature', 'initial', 'signature')); - - $metadataStore = new InMemoryMetadataStore([], ['signature' => ['isSignature' => ['user']]]); - $builder->setMetadataStore($metadataStore); - - $eventDispatcher = new EventDispatcher(); - $eventDispatcher->addSubscriber($eventSubscriber); - - $workflow = new Workflow($builder->build(), new EntityWorkflowMarkingStore(), $eventDispatcher, 'dummy'); - - $supports = new class () implements WorkflowSupportStrategyInterface { - public function supports(WorkflowInterface $workflow, object $subject): bool - { - return true; - } - }; - - $registry = new Registry(); - $registry->addWorkflow($workflow, $supports); - - return $registry; - } -} diff --git a/src/Bundle/ChillDocStoreBundle/Workflow/ConvertToPdfBeforeSignatureStepEventSubscriber.php b/src/Bundle/ChillDocStoreBundle/Workflow/ConvertToPdfBeforeSignatureStepEventSubscriber.php deleted file mode 100644 index 0d5fe9323..000000000 --- a/src/Bundle/ChillDocStoreBundle/Workflow/ConvertToPdfBeforeSignatureStepEventSubscriber.php +++ /dev/null @@ -1,75 +0,0 @@ - 'convertToPdfBeforeSignatureStepEvent', - ]; - } - - public function convertToPdfBeforeSignatureStepEvent(CompletedEvent $event): void - { - $entityWorkflow = $event->getSubject(); - if (!$entityWorkflow instanceof EntityWorkflow) { - return; - } - - $tos = $event->getTransition()->getTos(); - $workflow = $event->getWorkflow(); - $metadataStore = $workflow->getMetadataStore(); - - foreach ($tos as $to) { - $metadata = $metadataStore->getPlaceMetadata($to); - if (array_key_exists('isSignature', $metadata) && 0 < count($metadata['isSignature'])) { - $this->convertToPdf($entityWorkflow); - - return; - } - } - } - - private function convertToPdf(EntityWorkflow $entityWorkflow): void - { - $storedObject = $this->entityWorkflowManager->getAssociatedStoredObject($entityWorkflow); - - if (null === $storedObject) { - return; - } - - if ('application/pdf' === $storedObject->getCurrentVersion()->getType()) { - return; - } - - $this->storedObjectToPdfConverter->addConvertedVersion($storedObject, $this->requestStack->getCurrentRequest()->getLocale(), 'pdf'); - } -} From 03fe9a6d863f305d21aff6cea57da5901d65fc05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 15 Nov 2024 14:17:26 +0100 Subject: [PATCH 4/5] Update Signature App.vue to use a converted pdf Introduced a new helper ts function to download documents as PDFs and integrated with the existing workflow. Enhanced `PDFSignatureZoneAvailable` to implement `LocaleAwareInterface` for better locale management and added PDF conversion handling for non-PDF documents. Updated App.vue to use the new PDF download method. --- .../public/vuejs/DocumentSignature/App.vue | 7 ++--- .../vuejs/StoredObjectButton/helpers.ts | 27 +++++++++++++++++++ .../Signature/PDFSignatureZoneAvailable.php | 27 ++++++++++++++++--- .../PDFSignatureZoneAvailableTest.php | 2 ++ 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentSignature/App.vue b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentSignature/App.vue index d10f13a97..b46ecae3a 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentSignature/App.vue +++ b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/DocumentSignature/App.vue @@ -277,7 +277,7 @@ console.log(PdfWorker); // incredible but this is needed // pdfjsLib.GlobalWorkerOptions.workerSrc = PdfWorker; import Modal from "ChillMainAssets/vuejs/_components/Modal.vue"; -import { download_and_decrypt_doc } from "../StoredObjectButton/helpers"; +import {download_and_decrypt_doc, download_doc_as_pdf} from "../StoredObjectButton/helpers"; pdfjsLib.GlobalWorkerOptions.workerSrc = "pdfjs-dist/build/pdf.worker.mjs"; @@ -385,10 +385,7 @@ const init = () => downloadAndOpen().then(initPdf); async function downloadAndOpen(): Promise { let raw; try { - raw = await download_and_decrypt_doc( - signature.storedObject, - signature.storedObject.currentVersion - ); + raw = await download_doc_as_pdf(signature.storedObject); } catch (e) { console.error("error while downloading and decrypting document", e); throw e; diff --git a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/helpers.ts b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/helpers.ts index a5a520597..2fb55f71c 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/helpers.ts +++ b/src/Bundle/ChillDocStoreBundle/Resources/public/vuejs/StoredObjectButton/helpers.ts @@ -197,6 +197,32 @@ async function download_and_decrypt_doc(storedObject: StoredObject, atVersion: n } } +/** + * Fetch the stored object as a pdf. + * + * If the document is already in a pdf on the server side, the document is retrieved "as is" from the usual + * storage. + */ +async function download_doc_as_pdf(storedObject: StoredObject): Promise +{ + if (null === storedObject.currentVersion) { + throw new Error("the stored object does not count any version"); + } + + if (storedObject.currentVersion?.type === 'application/pdf') { + return download_and_decrypt_doc(storedObject, storedObject.currentVersion); + } + + const convertLink = build_convert_link(storedObject.uuid); + const response = await fetch(convertLink); + + if (!response.ok) { + throw new Error("Could not convert the document: " + response.status); + } + + return response.blob(); +} + async function is_object_ready(storedObject: StoredObject): Promise { const new_status_response = await window @@ -214,6 +240,7 @@ export { build_wopi_editor_link, download_and_decrypt_doc, download_doc, + download_doc_as_pdf, is_extension_editable, is_extension_viewable, is_object_ready, diff --git a/src/Bundle/ChillDocStoreBundle/Service/Signature/PDFSignatureZoneAvailable.php b/src/Bundle/ChillDocStoreBundle/Service/Signature/PDFSignatureZoneAvailable.php index d4109632a..67fbd89ba 100644 --- a/src/Bundle/ChillDocStoreBundle/Service/Signature/PDFSignatureZoneAvailable.php +++ b/src/Bundle/ChillDocStoreBundle/Service/Signature/PDFSignatureZoneAvailable.php @@ -17,15 +17,30 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum; use Chill\MainBundle\Entity\Workflow\EntityWorkflowStep; use Chill\MainBundle\Entity\Workflow\EntityWorkflowStepSignature; use Chill\MainBundle\Workflow\EntityWorkflowManager; +use Chill\WopiBundle\Service\WopiConverter; +use Symfony\Contracts\Translation\LocaleAwareInterface; -class PDFSignatureZoneAvailable +class PDFSignatureZoneAvailable implements LocaleAwareInterface { + private string $locale; + public function __construct( private readonly EntityWorkflowManager $entityWorkflowManager, private readonly PDFSignatureZoneParser $pdfSignatureZoneParser, private readonly StoredObjectManagerInterface $storedObjectManager, + private readonly WopiConverter $converter, ) {} + public function setLocale(string $locale) + { + $this->locale = $locale; + } + + public function getLocale() + { + return $this->locale; + } + /** * @return list */ @@ -38,10 +53,16 @@ class PDFSignatureZoneAvailable } if ('application/pdf' !== $storedObject->getType()) { - throw new \RuntimeException('Only PDF documents are supported'); + $content = $this->converter->convert($this->getLocale(), $this->storedObjectManager->read($storedObject), $storedObject->getType()); + } else { + $content = $this->storedObjectManager->read($storedObject); } - $zones = $this->pdfSignatureZoneParser->findSignatureZones($this->storedObjectManager->read($storedObject)); + $zones = $this->pdfSignatureZoneParser->findSignatureZones($content); + + // free some memory as soon as possible... + unset($content); + $signatureZonesIndexes = array_map( fn (EntityWorkflowStepSignature $step) => $step->getZoneSignatureIndex(), $this->collectSignaturesInUse($entityWorkflow) diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Service/Signature/PDFSignatureZoneAvailableTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Service/Signature/PDFSignatureZoneAvailableTest.php index ecc96bf89..ab4157936 100644 --- a/src/Bundle/ChillDocStoreBundle/Tests/Service/Signature/PDFSignatureZoneAvailableTest.php +++ b/src/Bundle/ChillDocStoreBundle/Tests/Service/Signature/PDFSignatureZoneAvailableTest.php @@ -22,6 +22,7 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum; use Chill\MainBundle\Workflow\EntityWorkflowManager; use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO; use Chill\PersonBundle\Entity\Person; +use Chill\WopiBundle\Service\WopiConverter; use PHPUnit\Framework\TestCase; use Prophecy\PhpUnit\ProphecyTrait; use Symfony\Component\Clock\MockClock; @@ -65,6 +66,7 @@ class PDFSignatureZoneAvailableTest extends TestCase $entityWorkflowManager->reveal(), $parser->reveal(), $storedObjectManager->reveal(), + $this->prophesize(WopiConverter::class)->reveal(), ); $actual = $filter->getAvailableSignatureZones($entityWorkflow); From b5f1f3153f75260699012d51d694ce7757af155d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 15 Nov 2024 14:17:57 +0100 Subject: [PATCH 5/5] Convert non-PDF documents before applying a signature Enhanced the `addConvertedVersion` method in `StoredObjectToPdfConverter` to optionally include converted content in the response. Updated `SignatureRequestController` to handle non-PDF documents by converting them to PDF before processing the signature request. --- .../Controller/SignatureRequestController.php | 16 +++++++++++++--- .../Service/StoredObjectToPdfConverter.php | 11 ++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/Bundle/ChillDocStoreBundle/Controller/SignatureRequestController.php b/src/Bundle/ChillDocStoreBundle/Controller/SignatureRequestController.php index b443779bb..913dde2d5 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/SignatureRequestController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/SignatureRequestController.php @@ -15,12 +15,14 @@ use Chill\DocStoreBundle\Service\Signature\Driver\BaseSigner\RequestPdfSignMessa use Chill\DocStoreBundle\Service\Signature\PDFPage; use Chill\DocStoreBundle\Service\Signature\PDFSignatureZone; use Chill\DocStoreBundle\Service\StoredObjectManagerInterface; +use Chill\DocStoreBundle\Service\StoredObjectToPdfConverter; 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\Templating\Entity\UserRender; use Chill\MainBundle\Workflow\EntityWorkflowManager; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -39,6 +41,8 @@ class SignatureRequestController private readonly ChillEntityRenderManagerInterface $entityRender, private readonly NormalizerInterface $normalizer, private readonly Security $security, + private readonly StoredObjectToPdfConverter $converter, + private readonly EntityManagerInterface $entityManager, ) {} #[Route('/api/1.0/document/workflow/{id}/signature-request', name: 'chill_docstore_signature_request')] @@ -53,11 +57,17 @@ class SignatureRequestController if (EntityWorkflowSignatureStateEnum::PENDING !== $signature->getState()) { return new JsonResponse([], status: Response::HTTP_CONFLICT); } - $storedObject = $this->entityWorkflowManager->getAssociatedStoredObject($entityWorkflow); - $content = $this->storedObjectManager->read($storedObject); - $data = \json_decode((string) $request->getContent(), true, 512, JSON_THROW_ON_ERROR); // TODO parse payload: json_decode ou, mieux, dataTransfertObject + if ('application/pdf' !== $storedObject->getType()) { + [$storedObject, $storedObjectVersion, $content] = $this->converter->addConvertedVersion($storedObject, $request->getLocale(), includeConvertedContent: true); + $this->entityManager->persist($storedObjectVersion); + $this->entityManager->flush(); + } else { + $content = $this->storedObjectManager->read($storedObject); + } + + $data = \json_decode((string) $request->getContent(), true, 512, JSON_THROW_ON_ERROR); $zone = new PDFSignatureZone( $data['zone']['index'], $data['zone']['x'], diff --git a/src/Bundle/ChillDocStoreBundle/Service/StoredObjectToPdfConverter.php b/src/Bundle/ChillDocStoreBundle/Service/StoredObjectToPdfConverter.php index abfcca4cc..ac570c513 100644 --- a/src/Bundle/ChillDocStoreBundle/Service/StoredObjectToPdfConverter.php +++ b/src/Bundle/ChillDocStoreBundle/Service/StoredObjectToPdfConverter.php @@ -39,13 +39,13 @@ class StoredObjectToPdfConverter * @param string $lang the language for the conversion context * @param string $convertTo The target format for the conversion. Default is 'pdf'. * - * @return array{0: StoredObjectPointInTime, 1: StoredObjectVersion} contains the point in time before conversion and the new version of the stored object + * @return array{0: StoredObjectPointInTime, 1: StoredObjectVersion, 2?: string} contains the point in time before conversion and the new version of the stored object. The converted content is included in the response if $includeConvertedContent is true * * @throws \UnexpectedValueException if the preferred mime type for the conversion is not found * @throws \RuntimeException if the conversion or storage of the new version fails * @throws StoredObjectManagerException */ - public function addConvertedVersion(StoredObject $storedObject, string $lang, $convertTo = 'pdf'): array + public function addConvertedVersion(StoredObject $storedObject, string $lang, $convertTo = 'pdf', bool $includeConvertedContent = false): array { $newMimeType = $this->mimeTypes->getMimeTypes($convertTo)[0] ?? null; @@ -70,6 +70,11 @@ class StoredObjectToPdfConverter $pointInTime = new StoredObjectPointInTime($currentVersion, StoredObjectPointInTimeReasonEnum::KEEP_BEFORE_CONVERSION); $version = $this->storedObjectManager->write($storedObject, $converted, $newMimeType); - return [$pointInTime, $version]; + if (!$includeConvertedContent) { + return [$pointInTime, $version]; + } + + return [$pointInTime, $version, $converted]; + } }