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.
This commit is contained in:
Julien Fastré 2024-10-08 15:15:58 +02:00
parent 118ae291e2
commit 3f80d62ca2
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
12 changed files with 228 additions and 5 deletions

View File

@ -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 %}
<h1>{{ 'workflow.public_link.shared_doc'|trans }}</h1>
{% set previous = send.entityWorkflowStepChained.previous %}
{% if previous is not null %}
{% if previous.transitionBy is not null %}
<p>{{ 'workflow.public_link.doc_shared_by_at_explanation'|trans({'byUser': previous.transitionBy|chill_entity_render_string( { 'at_date': previous.transitionAt } ), 'at': previous.transitionAt }) }}</p>
{% else %}
<p>{{ 'workflow.public_link.doc_shared_automatically_at_explanation'|trans({'at': previous.transitionAt}) }}</p>
{% endif %}
{% endif %}
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="card"">
<div class="card-body">
<h2 class="card-title">{{ title }}</h2>
<h3>{{ 'workflow.public_link.main_document'|trans }}</h3>
<ul class="record_actions slim small">
<li>
{{ storedObject|chill_document_download_only_button(storedObject.title(), false) }}
</li>
</ul>
</div>
</div>
</div>
</div>
{% endblock %}

View File

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

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\Workflow;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSend;
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
use Chill\MainBundle\Workflow\EntityWorkflowWithStoredObjectHandlerInterface;
use Chill\MainBundle\Workflow\Templating\EntityWorkflowViewMetadataDTO;
use Twig\Environment;
class WorkflowWithPublicViewDocumentHelper
{
public function __construct(private readonly Environment $twig) {}
public function render(EntityWorkflowSend $send, EntityWorkflowViewMetadataDTO $metadata, EntityWorkflowHandlerInterface&EntityWorkflowWithStoredObjectHandlerInterface $handler): string
{
$entityWorkflow = $send->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,
]
);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" >
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0" >
<title>{% block title %}{% endblock %}</title>
{% block head_custom %}{% endblock %}
<link rel="shortcut icon" href="{{ asset('build/images/favicon.ico') }}" type="image/x-icon">
{{ encore_entry_link_tags('mod_bootstrap') }}
{{ encore_entry_link_tags('mod_forkawesome') }}
{{ encore_entry_link_tags('chill') }}
{% block css %}{% endblock %}
</head>
<body>
<header>
<nav class="navbar navbar-dark bg-primary navbar-expand-md">
<div class="container-xxl">
<div class="col-4">
<a class="navbar-brand" href="{{ path('chill_main_homepage') }}">
{{ include('@ChillMain/Layout/_header-logo.html.twig') }}
</a>
</div>
<div class="col-8"></div>
</div>
</nav>
</header>
<div class="content" id="content">
<div class="container-xxl">
<div class="row justify-content-center my-5">
<div>
{% block public_content %}{% endblock %}
</div>
<div style="margin-top: 1rem;">
<p>
{{ 'workflow.public_link.shared_explanation_until_remaining'|trans({'expireAt': send.expireAt, 'viewsCount': metadata.viewsCount, 'viewsRemaining': metadata.viewsRemaining}) }}
</p>
</div>
</div>
</div>
</div>
{{ 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 %}
</body>
</html>

View File

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

View File

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

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Workflow\Templating;
/**
* This is a DTO to give some metadata about the vizualisation of the
* EntityWorkflowView.
*
* The aim is to give some information from the controller which show the public view and the
* handler which will render the view.
*/
final readonly class EntityWorkflowViewMetadataDTO
{
public function __construct(
public int $viewsCount,
public int $viewsRemaining,
) {}
}

View File

@ -69,6 +69,17 @@ workflow:
}
send_external_message:
document_available_until: Le lien sera valable jusqu'au {expiration, date, long} à {expiration, time, short}.
public_link:
shared_explanation_until_remaining: >-
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: >-