From 3f80d62ca2d6892ccdf37182f01739dec21c252e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 8 Oct 2024 15:15:58 +0200 Subject: [PATCH] Add public workflow view functionality Introduced the ability to render public views for workflows, including new templates, handlers, and metadata support. Updated entity interfaces and translations to enhance the public sharing of workflow documents. --- ...public_view_with_document_render.html.twig | 43 ++++++++++++++ ...ompanyingCourseDocumentWorkflowHandler.php | 11 +++- .../WorkflowWithPublicViewDocumentHelper.php | 45 ++++++++++++++ .../translations/messages+intl-icu.fr.yml | 8 +++ .../translations/messages.fr.yml | 4 ++ .../WorkflowViewSendPublicController.php | 7 ++- .../Entity/Workflow/EntityWorkflowSend.php | 11 ++++ ...workflow_view_send_public_layout.html.twig | 58 +++++++++++++++++++ .../Workflow/EntityWorkflowManager.php | 5 +- .../EntityWorkflowWithPublicViewInterface.php | 3 +- .../EntityWorkflowViewMetadataDTO.php | 27 +++++++++ .../translations/messages+intl-icu.fr.yaml | 11 ++++ 12 files changed, 228 insertions(+), 5 deletions(-) create mode 100644 src/Bundle/ChillDocStoreBundle/Resources/views/Workflow/public_view_with_document_render.html.twig create mode 100644 src/Bundle/ChillDocStoreBundle/Workflow/WorkflowWithPublicViewDocumentHelper.php create mode 100644 src/Bundle/ChillMainBundle/Resources/views/Workflow/workflow_view_send_public_layout.html.twig create mode 100644 src/Bundle/ChillMainBundle/Workflow/Templating/EntityWorkflowViewMetadataDTO.php diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/Workflow/public_view_with_document_render.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/Workflow/public_view_with_document_render.html.twig new file mode 100644 index 000000000..c286642d9 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/Workflow/public_view_with_document_render.html.twig @@ -0,0 +1,43 @@ +{% extends '@ChillMain/Workflow/workflow_view_send_public_layout.html.twig' %} + +{% block css %} + {{ parent() }} + {{ encore_entry_link_tags('mod_document_download_button') }} +{% endblock %} + +{% block js %} + {{ parent() }} + {{ encore_entry_script_tags('mod_document_download_button') }} +{% endblock %} + +{% block title %}{{ 'workflow.public_link.title'|trans }} - {{ title }}{% endblock %} + +{% block public_content %} +

{{ 'workflow.public_link.shared_doc'|trans }}

+ + {% set previous = send.entityWorkflowStepChained.previous %} + {% if previous is not null %} + {% if previous.transitionBy is not null %} +

{{ 'workflow.public_link.doc_shared_by_at_explanation'|trans({'byUser': previous.transitionBy|chill_entity_render_string( { 'at_date': previous.transitionAt } ), 'at': previous.transitionAt }) }}

+ {% else %} +

{{ 'workflow.public_link.doc_shared_automatically_at_explanation'|trans({'at': previous.transitionAt}) }}

+ {% endif %} + {% endif %} + +
+
+
+
+

{{ title }}

+

{{ 'workflow.public_link.main_document'|trans }}

+ +
    +
  • + {{ storedObject|chill_document_download_only_button(storedObject.title(), false) }} +
  • +
+
+
+
+
+{% endblock %} diff --git a/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentWorkflowHandler.php b/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentWorkflowHandler.php index bc8de6587..4f4655b94 100644 --- a/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentWorkflowHandler.php +++ b/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentWorkflowHandler.php @@ -16,20 +16,24 @@ use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository; use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter; use Chill\MainBundle\Entity\Workflow\EntityWorkflow; +use Chill\MainBundle\Entity\Workflow\EntityWorkflowSend; use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository; +use Chill\MainBundle\Workflow\EntityWorkflowWithPublicViewInterface; use Chill\MainBundle\Workflow\EntityWorkflowWithStoredObjectHandlerInterface; +use Chill\MainBundle\Workflow\Templating\EntityWorkflowViewMetadataDTO; use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Symfony\Contracts\Translation\TranslatorInterface; /** * @implements EntityWorkflowWithStoredObjectHandlerInterface */ -readonly class AccompanyingCourseDocumentWorkflowHandler implements EntityWorkflowWithStoredObjectHandlerInterface +final readonly class AccompanyingCourseDocumentWorkflowHandler implements EntityWorkflowWithStoredObjectHandlerInterface, EntityWorkflowWithPublicViewInterface { public function __construct( private TranslatorInterface $translator, private EntityWorkflowRepository $workflowRepository, private AccompanyingCourseDocumentRepository $repository, + private WorkflowWithPublicViewDocumentHelper $publicViewDocumentHelper, ) {} public function getDeletionRoles(): array @@ -136,4 +140,9 @@ readonly class AccompanyingCourseDocumentWorkflowHandler implements EntityWorkfl return $this->workflowRepository->findByRelatedEntity(AccompanyingCourseDocument::class, $object->getId()); } + + public function renderPublicView(EntityWorkflowSend $entityWorkflowSend, EntityWorkflowViewMetadataDTO $metadata): string + { + return $this->publicViewDocumentHelper->render($entityWorkflowSend, $metadata, $this); + } } diff --git a/src/Bundle/ChillDocStoreBundle/Workflow/WorkflowWithPublicViewDocumentHelper.php b/src/Bundle/ChillDocStoreBundle/Workflow/WorkflowWithPublicViewDocumentHelper.php new file mode 100644 index 000000000..5d23150e0 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/Workflow/WorkflowWithPublicViewDocumentHelper.php @@ -0,0 +1,45 @@ +getEntityWorkflowStep()->getEntityWorkflow(); + $storedObject = $handler->getAssociatedStoredObject($entityWorkflow); + + if (null === $storedObject) { + return 'document removed'; + } + + $title = $handler->getEntityTitle($entityWorkflow); + + return $this->twig->render( + '@ChillDocStore/Workflow/public_view_with_document_render.html.twig', + [ + 'title' => $title, + 'storedObject' => $storedObject, + 'send' => $send, + 'metadata' => $metadata, + ] + ); + } +} diff --git a/src/Bundle/ChillDocStoreBundle/translations/messages+intl-icu.fr.yml b/src/Bundle/ChillDocStoreBundle/translations/messages+intl-icu.fr.yml index 0132cdc4f..58a5193d1 100644 --- a/src/Bundle/ChillDocStoreBundle/translations/messages+intl-icu.fr.yml +++ b/src/Bundle/ChillDocStoreBundle/translations/messages+intl-icu.fr.yml @@ -1,3 +1,11 @@ acc_course_document: duplicated_at: >- Dupliqué le {at, date, long} à {at, time, short} + +workflow: + public_link: + doc_shared_by_at_explanation: >- + Le document a été partagé avec vous par {byUser}, le {at, date, long} à {at, time, short}. + doc_shared_automatically_at_explanation: >- + Le document a été partagé avec vous le {at, date, long} à {at, time, short} + diff --git a/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml b/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml index 4ba0307d7..08adfbe06 100644 --- a/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml @@ -80,6 +80,10 @@ online_edit_document: Éditer en ligne workflow: Document deleted: Document supprimé + public_link: + shared_doc: Document partagé + title: Document partagé + main_document: Document principal # ROLES accompanyingCourseDocument: Documents dans les parcours d'accompagnement diff --git a/src/Bundle/ChillMainBundle/Controller/WorkflowViewSendPublicController.php b/src/Bundle/ChillMainBundle/Controller/WorkflowViewSendPublicController.php index 084fcdce0..a3835c90e 100644 --- a/src/Bundle/ChillMainBundle/Controller/WorkflowViewSendPublicController.php +++ b/src/Bundle/ChillMainBundle/Controller/WorkflowViewSendPublicController.php @@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflowSend; use Chill\MainBundle\Entity\Workflow\EntityWorkflowSendView; use Chill\MainBundle\Workflow\EntityWorkflowManager; use Chill\MainBundle\Workflow\Exception\HandlerWithPublicViewNotFoundException; +use Chill\MainBundle\Workflow\Templating\EntityWorkflowViewMetadataDTO; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Clock\ClockInterface; @@ -64,8 +65,12 @@ final readonly class WorkflowViewSendPublicController } try { + $metadata = new EntityWorkflowViewMetadataDTO( + $workflowSend->getViews()->count(), + 100 - $workflowSend->getViews()->count(), + ); $response = new Response( - $this->entityWorkflowManager->renderPublicView($workflowSend), + $this->entityWorkflowManager->renderPublicView($workflowSend, $metadata), ); $view = new EntityWorkflowSendView($workflowSend, $this->clock->now(), $request->getClientIp()); diff --git a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowSend.php b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowSend.php index 186cf64e6..f3294bd55 100644 --- a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowSend.php +++ b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowSend.php @@ -124,6 +124,17 @@ class EntityWorkflowSend implements TrackCreationInterface return $this->entityWorkflowStep; } + public function getEntityWorkflowStepChained(): ?EntityWorkflowStep + { + foreach ($this->getEntityWorkflowStep()->getEntityWorkflow()->getStepsChained() as $step) { + if ($this->getEntityWorkflowStep() === $step) { + return $step; + } + } + + return null; + } + public function getUuid(): UuidInterface { return $this->uuid; diff --git a/src/Bundle/ChillMainBundle/Resources/views/Workflow/workflow_view_send_public_layout.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Workflow/workflow_view_send_public_layout.html.twig new file mode 100644 index 000000000..fd2c45959 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/Workflow/workflow_view_send_public_layout.html.twig @@ -0,0 +1,58 @@ + + + + + + + {% block title %}{% endblock %} + {% block head_custom %}{% endblock %} + + + {{ encore_entry_link_tags('mod_bootstrap') }} + {{ encore_entry_link_tags('mod_forkawesome') }} + {{ encore_entry_link_tags('chill') }} + + {% block css %}{% endblock %} + + + + +
+ +
+ +
+
+
+
+ {% block public_content %}{% endblock %} +
+
+

+ {{ 'workflow.public_link.shared_explanation_until_remaining'|trans({'expireAt': send.expireAt, 'viewsCount': metadata.viewsCount, 'viewsRemaining': metadata.viewsRemaining}) }} +

+
+
+
+
+ +{{ include('@ChillMain/Layout/_footer.html.twig', {'public_page': true}) }} + +{{ encore_entry_script_tags('mod_bootstrap') }} +{{ encore_entry_script_tags('mod_forkawesome') }} +{{ encore_entry_script_tags('chill') }} + +{% block js %}{% endblock %} + + diff --git a/src/Bundle/ChillMainBundle/Workflow/EntityWorkflowManager.php b/src/Bundle/ChillMainBundle/Workflow/EntityWorkflowManager.php index f054826c4..f1c87fd4e 100644 --- a/src/Bundle/ChillMainBundle/Workflow/EntityWorkflowManager.php +++ b/src/Bundle/ChillMainBundle/Workflow/EntityWorkflowManager.php @@ -16,6 +16,7 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflow; use Chill\MainBundle\Entity\Workflow\EntityWorkflowSend; use Chill\MainBundle\Workflow\Exception\HandlerNotFoundException; use Chill\MainBundle\Workflow\Exception\HandlerWithPublicViewNotFoundException; +use Chill\MainBundle\Workflow\Templating\EntityWorkflowViewMetadataDTO; use Symfony\Component\Workflow\Registry; /** @@ -80,13 +81,13 @@ class EntityWorkflowManager * * @throws HandlerWithPublicViewNotFoundException if no handler with public view is found */ - public function renderPublicView(EntityWorkflowSend $entityWorkflowSend): string + public function renderPublicView(EntityWorkflowSend $entityWorkflowSend, EntityWorkflowViewMetadataDTO $metadata): string { $entityWorkflow = $entityWorkflowSend->getEntityWorkflowStep()->getEntityWorkflow(); foreach ($this->handlers as $handler) { if ($handler instanceof EntityWorkflowWithPublicViewInterface && $handler->supports($entityWorkflow)) { - return $handler->renderPublicView($entityWorkflowSend); + return $handler->renderPublicView($entityWorkflowSend, $metadata); } } diff --git a/src/Bundle/ChillMainBundle/Workflow/EntityWorkflowWithPublicViewInterface.php b/src/Bundle/ChillMainBundle/Workflow/EntityWorkflowWithPublicViewInterface.php index 2d4eefb9e..5a51c5d00 100644 --- a/src/Bundle/ChillMainBundle/Workflow/EntityWorkflowWithPublicViewInterface.php +++ b/src/Bundle/ChillMainBundle/Workflow/EntityWorkflowWithPublicViewInterface.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Workflow; use Chill\MainBundle\Entity\Workflow\EntityWorkflowSend; +use Chill\MainBundle\Workflow\Templating\EntityWorkflowViewMetadataDTO; interface EntityWorkflowWithPublicViewInterface { @@ -20,5 +21,5 @@ interface EntityWorkflowWithPublicViewInterface * * The public view must be a safe html string */ - public function renderPublicView(EntityWorkflowSend $entityWorkflowSend): string; + public function renderPublicView(EntityWorkflowSend $entityWorkflowSend, EntityWorkflowViewMetadataDTO $metadata): string; } diff --git a/src/Bundle/ChillMainBundle/Workflow/Templating/EntityWorkflowViewMetadataDTO.php b/src/Bundle/ChillMainBundle/Workflow/Templating/EntityWorkflowViewMetadataDTO.php new file mode 100644 index 000000000..e3053b8e9 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Workflow/Templating/EntityWorkflowViewMetadataDTO.php @@ -0,0 +1,27 @@ +- + Ce partage sera actif jusqu'au {expireAt, time, short} à {expireAt, time, short}. {viewsCount, plural, + =0 {Ce partage n'a pas encore été visualisé} + one {Ce partage a été visualisé une fois} + other {Ce partage a été visualisé # fois} + }, {viewsRemaining, plural, + =0 {il ne reste plus aucune visualisation possible.} + one {il reste encore une visualisation possible.} + other {il reste encore # visualisations possibles.} + } duration: minute: >-