From 01b13f078e52f596be695fd0ca0459d6006f45bf Mon Sep 17 00:00:00 2001 From: andriyun Date: Tue, 29 Mar 2022 15:34:35 +0200 Subject: [PATCH 1/4] Implemented redirect route for task console to get better UX for users --- os2forms_forloeb.routing.yml | 9 ++ os2forms_forloeb.services.yml | 7 + .../ForloebTaskConsoleController.php | 136 ++++++++++++++++++ src/ForloebTaskConsole.php | 65 +++++++++ 4 files changed, 217 insertions(+) create mode 100644 os2forms_forloeb.routing.yml create mode 100644 os2forms_forloeb.services.yml create mode 100644 src/Controller/ForloebTaskConsoleController.php create mode 100644 src/ForloebTaskConsole.php diff --git a/os2forms_forloeb.routing.yml b/os2forms_forloeb.routing.yml new file mode 100644 index 0000000..c98c51d --- /dev/null +++ b/os2forms_forloeb.routing.yml @@ -0,0 +1,9 @@ +os2forms_forloeb.forloeb_task_console_controller_execute: + path: 'execute-foloeb-task' + defaults: + _controller: '\Drupal\os2forms_forloeb\Controller\ForloebTaskConsoleController::execute' + _title: 'Execute task' + requirements: + _permission: 'view maestro task console' + options: + no_cache: TRUE diff --git a/os2forms_forloeb.services.yml b/os2forms_forloeb.services.yml new file mode 100644 index 0000000..9e939cf --- /dev/null +++ b/os2forms_forloeb.services.yml @@ -0,0 +1,7 @@ +services: + logger.channel.os2forms_forloeb: + parent: logger.channel_base + arguments: ['os2forms_forloeb'] + os2forms_forloeb.task_console: + class: Drupal\os2forms_forloeb\ForloebTaskConsole + arguments: ['@entity_type.manager'] diff --git a/src/Controller/ForloebTaskConsoleController.php b/src/Controller/ForloebTaskConsoleController.php new file mode 100644 index 0000000..2c08059 --- /dev/null +++ b/src/Controller/ForloebTaskConsoleController.php @@ -0,0 +1,136 @@ +forloebTaskConsole = $forloeb_task_console; + $this->entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('os2forms_forloeb.task_console'), + $container->get('entity_type.manager') + ); + } + + /** + * Redirects to the task execution URL. + * + * In case it's not possible to define task, redirects to task console. + * + * @return RedirectResponse + * Redirect object. + */ + public function execute() { + $redirect_to = Url::fromRoute('maestro_taskconsole.taskconsole'); + + // Check webform submission token. + $token = \Drupal::request()->query->get('token', ''); + if ($token) { + $queueRecord = $this->forloebTaskConsole->getQueueIdByWebformSubmissionToken($token); + } + else { + // For empty token there is user last task from taskconsole queue. + $queueIDs = MaestroEngine::getAssignedTaskQueueIds(\Drupal::currentUser()->id()); + $queueRecord = count($queueIDs) ? $this->entityTypeManager->getStorage('maestro_queue')->load(end($queueIDs)) : NULL; + + // In case there are more than 1 task warning message will be shown. + if (count($queueIDs) > 1) { + $this->messenger()->addWarning($this->t('You have @amount @tasks available for you. See list of the all tasks on taskconsole', [ + ':tasksonsole' => Url::fromRoute('maestro_taskconsole.taskconsole')->toString(), + '@amount' => count($queueIDs), + '@tasks' => new PluralTranslatableMarkup(count($queueIDs), 'task','tasks'), + ])); + } + } + + // Processing QueueRecord to get execution URL to redirect to. + if ($queueRecord) { + $handler = $queueRecord->handler->getString(); + $query_options = [ + 'queueid' => $queueRecord->id(), + 'modal' => 'notmodal' + ]; + + // As inspiration MaestroTaskConsoleController::getTasks() method was used. + if ($handler && !empty($handler) && $queueRecord->is_interactive->getString() == '1') { + global $base_url; + $handler = str_replace($base_url, '', $handler); + $handler_type = TaskHandler::getType($handler); + + $handler_url_parts = UrlHelper::parse($handler); + $query_options += $handler_url_parts['query']; + + } + elseif ($queueRecord->is_interactive->getString() == '1' && empty($handler)) { + // Handler is empty. If this is an interactive task and has no handler, we're still OK. This is an interactive function that uses a default handler then. + $handler_type = 'function'; + } + else { + $this->messenger()->addWarning($this->t('Undefined handler')); + } + + switch ($handler_type) { + case 'external': + $redirect_to = Url::fromUri($handler, ['query' => $query_options]); + break; + + case 'internal': + $redirect_to = Url::fromUserInput($handler, ['query' => $query_options]); + break; + + case 'function': + $redirect_to = Url::fromRoute('maestro.execute', $query_options); + break; + } + } + else { + $this->messenger()->addWarning($this->t('No tasks found to execute.')); + } + + return new RedirectResponse($redirect_to->toString()); + } + +} diff --git a/src/ForloebTaskConsole.php b/src/ForloebTaskConsole.php new file mode 100644 index 0000000..769812c --- /dev/null +++ b/src/ForloebTaskConsole.php @@ -0,0 +1,65 @@ +entityTypeManager = $entity_type_manager; + } + + /** + * Gets MaestroQueue record by webforms submission token. + * + * @param string $token + * + * @return \Drupal\maestro\Entity\MaestroQueue|null + * Returns MaestroQueue entity or NULL + * + * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException + * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException + */ + public function getQueueIdByWebformSubmissionToken($token = '') { + $engine = new MaestroEngine(); + // Fetch the user's queue items. + $queueIDs = $engine->getAssignedTaskQueueIds(\Drupal::currentUser()->id()); + + foreach ($queueIDs as $queueID) { + $this->entityTypeManager->getStorage('maestro_queue')->resetCache([$queueID]); + /** @var \Drupal\maestro\Entity\MaestroQueue $queueRecord */ + $queueRecord = $this->entityTypeManager->getStorage('maestro_queue')->load($queueID); + $processID = $engine->getProcessIdFromQueueId($queueID); + $templateMachineName = $engine->getTemplateIdFromProcessId($processID); + + // Get user input from 'inherit_webform_unique_id' + $taskMachineName = $engine->getTaskIdFromQueueId($queueID); + $task = $engine->getTemplateTaskByID($templateMachineName, $taskMachineName); + + // Load its corresponding webform submission. + $sid = $engine->getEntityIdentiferByUniqueID($processID, $task['data']['inherit_webform_unique_id'] ?? ''); + $webform_submission = $sid ? WebformSubmission::load($sid) : NULL; + + if ($webform_submission && $webform_submission->getToken() != $token) { + return $queueRecord; + } + } + + return NULL; + } +} From 30f814aca42925d5f0ad84859c18e2bcd3b5d82d Mon Sep 17 00:00:00 2001 From: andriyun Date: Fri, 1 Apr 2022 16:46:35 +0200 Subject: [PATCH 2/4] Fixed condition to define correct queue id --- src/ForloebTaskConsole.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ForloebTaskConsole.php b/src/ForloebTaskConsole.php index 769812c..2fc2c6c 100644 --- a/src/ForloebTaskConsole.php +++ b/src/ForloebTaskConsole.php @@ -55,7 +55,8 @@ public function getQueueIdByWebformSubmissionToken($token = '') { $sid = $engine->getEntityIdentiferByUniqueID($processID, $task['data']['inherit_webform_unique_id'] ?? ''); $webform_submission = $sid ? WebformSubmission::load($sid) : NULL; - if ($webform_submission && $webform_submission->getToken() != $token) { + // Compare webform submission with token from request. + if ($webform_submission && $webform_submission->getToken() == $token) { return $queueRecord; } } From d22d7103c5429aa3703dd8b88c3ebcd8e694506a Mon Sep 17 00:00:00 2001 From: andriyun Date: Fri, 1 Apr 2022 16:47:03 +0200 Subject: [PATCH 3/4] Adjusted route with os2forms-forloeb namespace --- os2forms_forloeb.routing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os2forms_forloeb.routing.yml b/os2forms_forloeb.routing.yml index c98c51d..0686d1b 100644 --- a/os2forms_forloeb.routing.yml +++ b/os2forms_forloeb.routing.yml @@ -1,5 +1,5 @@ os2forms_forloeb.forloeb_task_console_controller_execute: - path: 'execute-foloeb-task' + path: 'os2forms-forloeb/execute-task' defaults: _controller: '\Drupal\os2forms_forloeb\Controller\ForloebTaskConsoleController::execute' _title: 'Execute task' From 075aeb1e1cfde99954bac0886691f2516e43ce01 Mon Sep 17 00:00:00 2001 From: andriyun Date: Fri, 1 Apr 2022 16:47:59 +0200 Subject: [PATCH 4/4] Refactored controller method with early return --- .../ForloebTaskConsoleController.php | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/Controller/ForloebTaskConsoleController.php b/src/Controller/ForloebTaskConsoleController.php index 2c08059..c8fb5d5 100644 --- a/src/Controller/ForloebTaskConsoleController.php +++ b/src/Controller/ForloebTaskConsoleController.php @@ -86,48 +86,48 @@ public function execute() { } } - // Processing QueueRecord to get execution URL to redirect to. - if ($queueRecord) { - $handler = $queueRecord->handler->getString(); - $query_options = [ - 'queueid' => $queueRecord->id(), - 'modal' => 'notmodal' - ]; - - // As inspiration MaestroTaskConsoleController::getTasks() method was used. - if ($handler && !empty($handler) && $queueRecord->is_interactive->getString() == '1') { - global $base_url; - $handler = str_replace($base_url, '', $handler); - $handler_type = TaskHandler::getType($handler); - - $handler_url_parts = UrlHelper::parse($handler); - $query_options += $handler_url_parts['query']; + if (empty($queueRecord)) { + $this->messenger()->addWarning($this->t('No tasks found to execute.')); + return new RedirectResponse($redirect_to->toString()); + } - } - elseif ($queueRecord->is_interactive->getString() == '1' && empty($handler)) { - // Handler is empty. If this is an interactive task and has no handler, we're still OK. This is an interactive function that uses a default handler then. - $handler_type = 'function'; - } - else { - $this->messenger()->addWarning($this->t('Undefined handler')); - } + // Processing QueueRecord to get execution URL to redirect to. + $handler = $queueRecord->handler->getString(); + $query_options = [ + 'queueid' => $queueRecord->id(), + 'modal' => 'notmodal' + ]; - switch ($handler_type) { - case 'external': - $redirect_to = Url::fromUri($handler, ['query' => $query_options]); - break; + // As inspiration MaestroTaskConsoleController::getTasks() method was used. + if ($handler && !empty($handler) && $queueRecord->is_interactive->getString() == '1') { + global $base_url; + $handler = str_replace($base_url, '', $handler); + $handler_type = TaskHandler::getType($handler); - case 'internal': - $redirect_to = Url::fromUserInput($handler, ['query' => $query_options]); - break; + $handler_url_parts = UrlHelper::parse($handler); + $query_options += $handler_url_parts['query']; - case 'function': - $redirect_to = Url::fromRoute('maestro.execute', $query_options); - break; - } + } + elseif ($queueRecord->is_interactive->getString() == '1' && empty($handler)) { + // Handler is empty. If this is an interactive task and has no handler, we're still OK. This is an interactive function that uses a default handler then. + $handler_type = 'function'; } else { - $this->messenger()->addWarning($this->t('No tasks found to execute.')); + $this->messenger()->addWarning($this->t('Undefined handler')); + } + + switch ($handler_type) { + case 'external': + $redirect_to = Url::fromUri($handler, ['query' => $query_options]); + break; + + case 'internal': + $redirect_to = Url::fromUserInput($handler, ['query' => $query_options]); + break; + + case 'function': + $redirect_to = Url::fromRoute('maestro.execute', $query_options); + break; } return new RedirectResponse($redirect_to->toString());