diff --git a/web/sites/default/modules/os2forms_forloeb/os2forms_forloeb.module b/web/sites/default/modules/os2forms_forloeb/os2forms_forloeb.module index fa6289ea..ac30e6ed 100644 --- a/web/sites/default/modules/os2forms_forloeb/os2forms_forloeb.module +++ b/web/sites/default/modules/os2forms_forloeb/os2forms_forloeb.module @@ -329,6 +329,22 @@ function os2forms_forloeb_mail_alter(&$message) { * Implements hook_theme(). */ function os2forms_forloeb_theme(array &$variables) { + $theme['os2forms_forloeb_notification_preview'] = [ + 'variables' => [ + 'webform' => NULL, + 'handler' => NULL, + 'type' => NULL, + 'submission' => NULL, + 'return_url' => NULL, + 'render_url' => NULL, + 'preview_urls' => [ + 'prev' => NULL, + 'self' => NULL, + 'next' => NULL, + ], + ], + ]; + $theme['os2forms_forloeb_notification_message_email_html'] = [ 'variables' => [ 'message' => [ diff --git a/web/sites/default/modules/os2forms_forloeb/os2forms_forloeb.routing.yml b/web/sites/default/modules/os2forms_forloeb/os2forms_forloeb.routing.yml index 44803e50..7f0c28d8 100644 --- a/web/sites/default/modules/os2forms_forloeb/os2forms_forloeb.routing.yml +++ b/web/sites/default/modules/os2forms_forloeb/os2forms_forloeb.routing.yml @@ -5,3 +5,37 @@ os2forms_forloeb.settings: _title: 'OS2Forms forløb' requirements: _permission: 'administer site configuration' + +os2forms_forloeb.meastro_notification.preview: + path: '/admin/structure/webform/manage/{webform}/os2forms_forloeb/{handler}/preview/{content_type}' + defaults: + _controller: '\Drupal\os2forms_forloeb\Controller\MaestroNotificationController::preview' + _title: 'Maestro notification preview' + options: + parameters: + webform: + type: 'entity:webform' + requirements: + _permission: 'view any webform submission' + +os2forms_forloeb.meastro_notification.preview_render: + path: '/admin/structure/webform/manage/{webform}/os2forms_forloeb/{handler}/preview/{content_type}/render/{submission}' + defaults: + _controller: '\Drupal\os2forms_forloeb\Controller\MaestroNotificationController::previewRender' + _title: 'Maestro notification render preview' + options: + parameters: + webform: + type: 'entity:webform' + submission: + type: 'entity:webform_submission' + requirements: + _permission: 'view any webform submission' + +os2forms_forloeb.meastro_notification.preview_message: + path: '/os2forms_forloeb/notification/message' + defaults: + _controller: '\Drupal\os2forms_forloeb\Controller\MaestroNotificationController::message' + _title: 'Maestro notification message' + requirements: + _permission: 'view any webform submission' diff --git a/web/sites/default/modules/os2forms_forloeb/src/Controller/MaestroNotificationController.php b/web/sites/default/modules/os2forms_forloeb/src/Controller/MaestroNotificationController.php new file mode 100644 index 00000000..b7e966d9 --- /dev/null +++ b/web/sites/default/modules/os2forms_forloeb/src/Controller/MaestroNotificationController.php @@ -0,0 +1,119 @@ +get('entity_type.manager')->getStorage('webform_submission'), + $container->get(MaestroHelper::class) + ); + } + + /** + * Preview action. + */ + public function preview(Request $request, WebformInterface $webform, string $handler, string $content_type, RouteMatchInterface $routeMatch) { + $submissionIds = array_keys($this->webformSubmissionStorage->getQuery() + ->condition('webform_id', $webform->id()) + ->sort('created', 'DESC') + ->execute()); + $currentSubmission = (int) $request->query->get('submission'); + $index = array_search($currentSubmission, $submissionIds); + if (FALSE === $index) { + $currentSubmission = reset($submissionIds) ?: NULL; + $index = array_search($currentSubmission, $submissionIds); + } + + $previewUrls = array_map( + static fn ($submission) => Url::fromRoute('os2forms_forloeb.meastro_notification.preview', [ + 'webform' => $webform->id(), + 'handler' => $handler, + 'content_type' => $content_type, + 'submission' => $submission, + ]), + array_filter([ + 'prev' => $submissionIds[$index + 1] ?? NULL, + 'self' => $currentSubmission, + 'next' => $submissionIds[$index - 1] ?? NULL, + ]) + ); + + $renderUrl = NULL !== $currentSubmission + ? Url::fromRoute('os2forms_forloeb.meastro_notification.preview_render', [ + 'webform' => $webform->id(), + 'handler' => $handler, + 'content_type' => $content_type, + 'submission' => $currentSubmission, + ]) + : NULL; + + return [ + '#theme' => 'os2forms_forloeb_notification_preview', + '#webform' => $webform, + '#handler' => $handler, + '#type' => $content_type, + '#submission' => $currentSubmission, + '#return_url' => $webform->toUrl('handlers'), + '#render_url' => $renderUrl, + '#preview_urls' => $previewUrls, + ]; + } + + /** + * Render notification preview. + */ + public function previewRender(Request $request, WebformInterface $webform, string $handler, string $content_type, WebformSubmissionInterface $submission) { + $templateTask = []; + $maestroQueueID = 0; + [$content, $contentType] = $this->maestroHelper->renderNotification($submission, $handler, $templateTask, $maestroQueueID, $content_type); + + $response = new Response($content); + if ('pdf' === $contentType) { + $response->headers->set('content-type', Document::MIME_TYPE_PDF); + } + + return $response; + } + + /** + * Message action. + */ + public function message(Request $request): Response { + $content[] = '

' . $request->get('message') . '

'; + if ($referer = $request->headers->get('referer')) { + $content[] = sprintf('Go back', $referer); + } + + return new Response(implode(PHP_EOL, $content)); + } + +} diff --git a/web/sites/default/modules/os2forms_forloeb/src/MaestroHelper.php b/web/sites/default/modules/os2forms_forloeb/src/MaestroHelper.php index a1672d9d..44e2f505 100644 --- a/web/sites/default/modules/os2forms_forloeb/src/MaestroHelper.php +++ b/web/sites/default/modules/os2forms_forloeb/src/MaestroHelper.php @@ -18,6 +18,7 @@ use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\Core\Mail\MailManagerInterface; use Drupal\Core\Render\Markup; +use Drupal\Core\Url; use Drupal\maestro\Engine\MaestroEngine; use Drupal\maestro\Utility\TaskHandler; use Drupal\os2forms_digital_post\Helper\DigitalPostHelper; @@ -205,56 +206,26 @@ private function sendNotification( ]; try { - $data = $submission->getData(); - $webform = $submission->getWebform(); - $handlers = $webform->getHandlers(); + $handlers = $submission->getWebform()->getHandlers(); foreach ($handlers as $handler) { if (!($handler instanceof MaestroNotificationHandler) || $handler->isDisabled() || $handler->isExcluded()) { continue; } - $settings = $handler->getSettings(); - $notificationSetting = $settings[MaestroNotificationHandler::NOTIFICATION]; - $recipientElement = $notificationSetting[MaestroNotificationHandler::RECIPIENT_ELEMENT] ?? NULL; - $recipient = - // Handle os2forms_person_lookup element. - $data[$recipientElement]['cpr_number'] - // Simple element. - ?? $data[$recipientElement] - ?? NULL; - if (NULL !== $recipient) { - // Lifted from MaestroEngine. - $maestroTokenData = [ - 'maestro' => [ - 'task' => $templateTask, - 'queueID' => $maestroQueueID, - ], - ]; - - $subject = $this->tokenManager->replace( - $notificationSetting[MaestroNotificationHandler::NOTIFICATION_SUBJECT], - $submission, - $maestroTokenData - ); - - $content = $notificationSetting[MaestroNotificationHandler::NOTIFICATION_CONTENT]; - if (isset($content['value'])) { - // Process tokens in content. - $content['value'] = $this->tokenManager->replace( - $content['value'], - $submission, - $maestroTokenData - ); - } - - $taskUrl = TaskHandler::getHandlerURL($maestroQueueID); - $actionLabel = $notificationSetting[MaestroNotificationHandler::NOTIFICATION_ACTION_LABEL]; - if (filter_var($recipient, FILTER_VALIDATE_EMAIL)) { - $this->sendNotificationEmail($recipient, $subject, $content, $taskUrl, $actionLabel, $submission); - } - else { - $this->sendNotificationDigitalPost($recipient, $subject, $content, $taskUrl, $actionLabel, $submission); - } + [ + $content, + $contentType, + $recipient, + $subject, + $taskUrl, + $actionLabel, + ] = $this->renderNotification($submission, $handler->getHandlerId(), $templateTask, $maestroQueueID); + + if ('email' === $contentType) { + $this->sendNotificationEmail($recipient, $subject, $content, $submission); + } + else { + $this->sendNotificationDigitalPost($recipient, $subject, $content, $taskUrl, $actionLabel, $submission); } } } @@ -297,13 +268,9 @@ private function loadQueue(): QueueInterface { private function sendNotificationEmail( string $recipient, string $subject, - array $content, - string $taskUrl, - string $actionLabel, + string $body, WebformSubmissionInterface $submission ): void { - $body = $this->buildHtml('os2forms_forloeb_notification_message_email_html', $subject, $content, $taskUrl, $actionLabel, $submission); - $message = [ 'subject' => $subject, 'body' => $body, @@ -338,26 +305,18 @@ private function sendNotificationEmail( private function sendNotificationDigitalPost( string $recipient, string $subject, - array $content, + string $content, string $taskUrl, string $actionLabel, WebformSubmissionInterface $submission - ): void - { + ): void { if (!$this->moduleHandler->moduleExists('os2forms_digital_post')) { throw new RuntimeException('Cannot send digital post. Module os2forms_digital_post not installed.'); } try { - $pdfBody = $this->buildHtml('os2forms_forloeb_notification_message_pdf_html', $subject, $content, $taskUrl, - $actionLabel, $submission); - $dompdf = new Dompdf(); - $dompdf->loadHtml($pdfBody); - $dompdf->render(); - $pdfContent = $dompdf->output(); - $document = new Document( - $pdfContent, + $content, Document::MIME_TYPE_PDF, $subject . '.pdf' ); @@ -371,8 +330,8 @@ private function sendNotificationDigitalPost( ->setActionCode(SF1601::ACTION_SELVBETJENING) ->setEntryPoint((new EntryPoint()) ->setUrl($taskUrl) - ) - ->setLabel($actionLabel) + ) + ->setLabel($actionLabel), ]; $message = $this->digitalPostHelper->getMeMoHelper()->buildMessage($recipientLookupResult, $senderLabel, @@ -391,7 +350,8 @@ private function sendNotificationDigitalPost( 'handler_id' => 'os2forms_forloeb', 'operation' => 'notification sent', ]); - } catch (\Exception $exception) { + } + catch (\Exception $exception) { $this->error('Error sending digital post: @message', [ '@message' => $exception->getMessage(), 'webform_submission' => $submission, @@ -401,11 +361,128 @@ private function sendNotificationDigitalPost( } } + /** + * Render notification. + * + * @param \Drupal\webform\WebformSubmissionInterface $submission + * The submission. + * @param string $handlerId + * The handler ID. + * @param array $templateTask + * The Maestro template task. + * @param int $maestroQueueID + * The Maestro queue ID. + * @param string|null $contentType + * Optional content type. If not set the content type will be compoted based + * on the recipient. + * + * @return array + * The rendered notification as a list + * - Content + * - Content type + * - Recipient + * - Subject + * - Task URL (for digital post) + * - Action label (for digital post) + */ + public function renderNotification(WebformSubmissionInterface $submission, string $handlerId, array $templateTask, int $maestroQueueID, string $contentType = NULL): array { + $handler = $submission->getWebform()->getHandler($handlerId); + $settings = $handler->getSettings(); + $notificationSetting = $settings[MaestroNotificationHandler::NOTIFICATION]; + + $data = $submission->getData(); + $recipientElement = $notificationSetting[MaestroNotificationHandler::RECIPIENT_ELEMENT] ?? NULL; + // Handle os2forms_person_lookup element. + $recipient = $data[$recipientElement]['cpr_number'] + // Simple element. + ?? $data[$recipientElement] + ?? NULL; + + if (NULL !== $recipient) { + // Lifted from MaestroEngine. + $maestroTokenData = [ + 'maestro' => [ + 'task' => $templateTask, + 'queueID' => $maestroQueueID, + ], + ]; + + $processValue = static fn (string $value) => $value; + + // Handle a preview, i.e. not a real Maestro context. + if (empty($templateTask) || 0 === $maestroQueueID) { + $taskUrl = Url::fromRoute('os2forms_forloeb.meastro_notification.preview_message', ['message' => 'This is just a preview'])->toString(TRUE)->getGeneratedUrl(); + + $processValue = static function (string $value) use ($taskUrl) { + // Replace href="[maestro:task-url]" with href="«$taskUrl»". + $value = preg_replace('/href\s*=\s*["\']\[maestro:task-url\]["\']/', sprintf('href="%s"', htmlspecialchars($taskUrl)), $value); + $value = preg_replace('/\[(maestro:[^]]+)\]/', '[\1]', $value); + + return $value; + }; + } + else { + $taskUrl = TaskHandler::getHandlerURL($maestroQueueID); + } + + $subject = $this->tokenManager->replace( + $processValue($notificationSetting[MaestroNotificationHandler::NOTIFICATION_SUBJECT]), + $submission, + $maestroTokenData + ); + + $content = $notificationSetting[MaestroNotificationHandler::NOTIFICATION_CONTENT]; + if (isset($content['value'])) { + // Process tokens in content. + $content['value'] = $this->tokenManager->replace( + $processValue($content['value']), + $submission, + $maestroTokenData + ); + } + + $actionLabel = $this->tokenManager->replace($notificationSetting[MaestroNotificationHandler::NOTIFICATION_ACTION_LABEL], $submission); + + if (NULL === $contentType) { + $contentType = filter_var($recipient, FILTER_VALIDATE_EMAIL) ? 'email' : 'pdf'; + } + + switch ($contentType) { + case 'email': + $content = $this->buildHtml($contentType, $subject, $content, $taskUrl, $actionLabel, $submission); + break; + + case 'pdf': + $pdfContent = $this->buildHtml($contentType, $subject, $content, $taskUrl, $actionLabel, $submission); + $dompdf = new Dompdf(); + $dompdf->loadHtml($pdfContent); + $dompdf->render(); + + $content = $dompdf->output(); + break; + + default: + throw new RuntimeException(sprintf('Invalid content type: %s', $contentType)); + } + + return [ + $content, + $contentType, + $recipient, + $subject, + $taskUrl, + $actionLabel, + ]; + } + + throw new RuntimeException(); + } + /** * Build HTML. */ private function buildHtml( - string $theme, + string $type, string $subject, array $content, string $taskUrl, @@ -413,6 +490,8 @@ private function buildHtml( WebformSubmissionInterface $submission ): string|MarkupInterface { // Render body as HTML. + $theme = sprintf('os2forms_forloeb_notification_message_%s_html', $type); + $build = [ '#theme' => $theme, '#message' => [ diff --git a/web/sites/default/modules/os2forms_forloeb/src/Plugin/WebformHandler/MaestroNotificationHandler.php b/web/sites/default/modules/os2forms_forloeb/src/Plugin/WebformHandler/MaestroNotificationHandler.php index 37dfb8f9..445b164f 100644 --- a/web/sites/default/modules/os2forms_forloeb/src/Plugin/WebformHandler/MaestroNotificationHandler.php +++ b/web/sites/default/modules/os2forms_forloeb/src/Plugin/WebformHandler/MaestroNotificationHandler.php @@ -3,6 +3,7 @@ namespace Drupal\os2forms_forloeb\Plugin\WebformHandler; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Link; use Drupal\webform\Plugin\WebformHandlerBase; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -63,9 +64,25 @@ public static function create(ContainerInterface $container, array $configuratio */ public function getSummary() { return [ - '#markup' => $this->t('Sends notification when triggered by Maestro. The notification will be sent to the person identified by the value of the %element element.', [ - '%element' => $this->configuration[self::NOTIFICATION][self::RECIPIENT_ELEMENT] ?? NULL, - ]), + 'info' => [ + '#prefix' => '
', + '#suffix' => '
', + '#markup' => $this->t('Sends notification when triggered by Maestro. The notification will be sent to the person identified by the value of the %element element.', [ + '%element' => $this->configuration[self::NOTIFICATION][self::RECIPIENT_ELEMENT] ?? NULL, + ]), + ], + 'preview' => [ + '#prefix' => '
', + '#suffix' => '
', + ] + + Link::createFromRoute( + $this->t('Preview notifications'), + 'os2forms_forloeb.meastro_notification.preview', [ + 'webform' => $this->getWebform()->id(), + 'handler' => $this->getHandlerId(), + 'content_type' => 'email', + ] + )->toRenderable(), ]; } diff --git a/web/sites/default/modules/os2forms_forloeb/templates/os2forms-forloeb-notification-preview.html.twig b/web/sites/default/modules/os2forms_forloeb/templates/os2forms-forloeb-notification-preview.html.twig new file mode 100644 index 00000000..7871a016 --- /dev/null +++ b/web/sites/default/modules/os2forms_forloeb/templates/os2forms-forloeb-notification-preview.html.twig @@ -0,0 +1,56 @@ +{# + /** + * @file + * Template for Maestro notification preview. + * + * Available variables: + * - preview_urls: The preview URLs + * - prev: Previous submission preview URL (if any) + * - self: The current preview URL (if any) + * - next: Next submission preview URL (if any) + * - webform: The webform + * - handler: The handler ID + * - content_type: The content type (email, pdf) + * - submission: The submission ID + * - return_url: The return URL (to list of webform handlers) + * - render_url: The render URL to render the actual preview + */ + #} +
+ + + + + {% if render_url %} + + {% endif %} +