From ed0e390a511da1d2f61dbae24fcc61463ee558e4 Mon Sep 17 00:00:00 2001 From: andriyun Date: Tue, 5 Apr 2022 07:54:04 +0200 Subject: [PATCH 1/4] OS2FORMS-371 Added token for easy getting os2forms execute task link in mail handlers --- os2forms_forloeb.module | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/os2forms_forloeb.module b/os2forms_forloeb.module index 2002cf8..f497951 100644 --- a/os2forms_forloeb.module +++ b/os2forms_forloeb.module @@ -2,6 +2,8 @@ use Drupal\webform\WebformInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Render\BubbleableMetadata; +use Drupal\Core\Url; use Drupal\maestro\Engine\MaestroEngine; use Drupal\webform\Entity\WebformSubmission; use Drupal\user\Entity\User; @@ -201,7 +203,7 @@ function os2forms_forloeb_spv_fetch_entity_username($uniqueWebformIdentifier, $w /** * Returns array of custom task-types for OS2forms - * + * */ function os2forms_forloeb_get_custom_task_types() { return ['MaestroWebformMultiple', 'MaestroWebformInherit']; @@ -268,3 +270,33 @@ function os2forms_forloeb_form_alter(&$form, FormStateInterface $form_state, $fo function os2forms_forloeb_preprocess_page(&$variables) { $variables['#attached']['library'][] = 'os2forms_forloeb/os2forms_forloeb'; } + +/** + * Implements hook_token_info_alter(). + */ +function os2forms_forloeb_token_info_alter(&$data) { + $data['tokens']['webform_submission']['os2forms_forloeb_execute_task'] = [ + 'name' => t('Execute task path for webform submission'), + 'description' => t("The token that can be user to get path for webform submission redirect URL."), + 'type' => 'webform_submission', + ]; +} + +/** + * Implements hook_tokens(). + * + * Provides token value for webform_submission:os2forms_forloeb_execute_task. + */ +function os2forms_forloeb_tokens($type, array $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) { + $replacements = []; + + if ($type === 'webform_submission' && !empty($data['webform_submission']) && isset($tokens['os2forms_forloeb_execute_task'])) { + $replacements[$tokens['os2forms_forloeb_execute_task']] = Url::fromRoute( + 'os2forms_forloeb.forloeb_task_console_controller_execute', + ['token' => $data['webform_submission']->getToken()], + ['absolute' => TRUE] + )->toString(TRUE)->getGeneratedUrl(); + } + + return $replacements; +} From f92e668e5af4671df9666a9e9928b6a7a47806dc Mon Sep 17 00:00:00 2001 From: andriyun Date: Thu, 7 Apr 2022 14:11:29 +0200 Subject: [PATCH 2/4] Added lookup for queue id based on webform token --- os2forms_forloeb.routing.yml | 2 +- src/ForloebTaskConsole.php | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/os2forms_forloeb.routing.yml b/os2forms_forloeb.routing.yml index 0686d1b..5754153 100644 --- a/os2forms_forloeb.routing.yml +++ b/os2forms_forloeb.routing.yml @@ -4,6 +4,6 @@ os2forms_forloeb.forloeb_task_console_controller_execute: _controller: '\Drupal\os2forms_forloeb\Controller\ForloebTaskConsoleController::execute' _title: 'Execute task' requirements: - _permission: 'view maestro task console' + _permission: 'access content' options: no_cache: TRUE diff --git a/src/ForloebTaskConsole.php b/src/ForloebTaskConsole.php index 2fc2c6c..2674f3e 100644 --- a/src/ForloebTaskConsole.php +++ b/src/ForloebTaskConsole.php @@ -3,6 +3,8 @@ namespace Drupal\os2forms_forloeb; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\maestro\Engine\MaestroEngine; +use Drupal\maestro\Entity\MaestroEntityIdentifiers; +use Drupal\maestro\Entity\MaestroProcess; use Drupal\webform\Entity\WebformSubmission; /** @@ -36,6 +38,24 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager) { * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ public function getQueueIdByWebformSubmissionToken($token = '') { + /** @var WebformSubmission $webform_submission */ + $webform_submissions = $this->entityTypeManager->getStorage('webform_submission')->loadByProperties(['token' => $token]); + $webform_submission = reset($webform_submissions); + /** @var MaestroEntityIdentifiers $maestro_entity_identifier */ + $maestro_entity_identifiers = $this->entityTypeManager->getStorage('maestro_entity_identifiers')->loadByProperties([ + 'entity_type' => 'webform_submission', + 'entity_id' => $webform_submission->id(), + ]); + $maestro_entity_identifier = reset($maestro_entity_identifiers); + $processIDs = $maestro_entity_identifier->process_id->referencedEntities(); + $processID = reset($processIDs); + $maestro_queues = $this->entityTypeManager->getStorage('maestro_queue')->loadByProperties([ + 'process_id' => $processID->id(), + 'task_class_name' => 'MaestroWebformInherit', + ]); + $maestro_queue = reset($maestro_queues); + return $maestro_queue; + $engine = new MaestroEngine(); // Fetch the user's queue items. $queueIDs = $engine->getAssignedTaskQueueIds(\Drupal::currentUser()->id()); From d98addbd4544955660b10db329c27c6d9ca8e2e7 Mon Sep 17 00:00:00 2001 From: andriyun Date: Tue, 26 Apr 2022 16:18:41 +0200 Subject: [PATCH 3/4] OS2FORMS-371 Added access bypassing based on webforms submission token. --- os2forms_forloeb.module | 28 +++++++- os2forms_forloeb.services.yml | 2 +- .../ForloebTaskConsoleController.php | 5 +- src/ForloebTaskConsole.php | 68 +++++++++---------- .../EngineTasks/MaestroWebformInheritTask.php | 19 +++++- 5 files changed, 80 insertions(+), 42 deletions(-) diff --git a/os2forms_forloeb.module b/os2forms_forloeb.module index f497951..125f4a4 100644 --- a/os2forms_forloeb.module +++ b/os2forms_forloeb.module @@ -293,10 +293,36 @@ function os2forms_forloeb_tokens($type, array $tokens, array $data, array $optio if ($type === 'webform_submission' && !empty($data['webform_submission']) && isset($tokens['os2forms_forloeb_execute_task'])) { $replacements[$tokens['os2forms_forloeb_execute_task']] = Url::fromRoute( 'os2forms_forloeb.forloeb_task_console_controller_execute', - ['token' => $data['webform_submission']->getToken()], + ['os2forms-forloeb-ws-token' => $data['webform_submission']->getToken()], ['absolute' => TRUE] )->toString(TRUE)->getGeneratedUrl(); } return $replacements; } + +/** + * Implements hook_entity_access(). + * Allows requests with tokens to view the entity. + */ +function os2forms_forloeb_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) { + if ($operation == 'update' && $entity instanceof WebformSubmission) { + $token = \Drupal::request()->query->get('os2forms-forloeb-ws-token'); + if ($token && $token == $entity->getToken()) { + return \Drupal\Core\Access\AccessResult::allowed(); + } + } +} + +/** + * Implements hook_maestro_post_fetch_assigned_queue_tasks(). + */ +function os2forms_forloeb_maestro_post_fetch_assigned_queue_tasks($userID, &$queueIDs) { + $token = \Drupal::request()->query->get('os2forms-forloeb-ws-token', ''); + if ($token) { + $forloebTaskConsole = Drupal::service('os2forms_forloeb.task_console'); + $queueRecord = $forloebTaskConsole->getQueueIdByWebformSubmissionToken($token); + $queueIDs[] = $queueRecord->id(); + $queueIDs = array_unique($queueIDs); + } +} diff --git a/os2forms_forloeb.services.yml b/os2forms_forloeb.services.yml index 9e939cf..eb0fa89 100644 --- a/os2forms_forloeb.services.yml +++ b/os2forms_forloeb.services.yml @@ -4,4 +4,4 @@ services: arguments: ['os2forms_forloeb'] os2forms_forloeb.task_console: class: Drupal\os2forms_forloeb\ForloebTaskConsole - arguments: ['@entity_type.manager'] + arguments: ['@entity_type.manager', '@logger.channel.os2forms_forloeb'] diff --git a/src/Controller/ForloebTaskConsoleController.php b/src/Controller/ForloebTaskConsoleController.php index c8fb5d5..0666915 100644 --- a/src/Controller/ForloebTaskConsoleController.php +++ b/src/Controller/ForloebTaskConsoleController.php @@ -67,7 +67,7 @@ public function execute() { $redirect_to = Url::fromRoute('maestro_taskconsole.taskconsole'); // Check webform submission token. - $token = \Drupal::request()->query->get('token', ''); + $token = \Drupal::request()->query->get('os2forms-forloeb-ws-token', ''); if ($token) { $queueRecord = $this->forloebTaskConsole->getQueueIdByWebformSubmissionToken($token); } @@ -126,6 +126,9 @@ public function execute() { break; case 'function': + if ($token) { + $query_options['os2forms-forloeb-ws-token'] = $token; + } $redirect_to = Url::fromRoute('maestro.execute', $query_options); break; } diff --git a/src/ForloebTaskConsole.php b/src/ForloebTaskConsole.php index 2674f3e..ef7340c 100644 --- a/src/ForloebTaskConsole.php +++ b/src/ForloebTaskConsole.php @@ -2,16 +2,20 @@ namespace Drupal\os2forms_forloeb; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\maestro\Engine\MaestroEngine; use Drupal\maestro\Entity\MaestroEntityIdentifiers; use Drupal\maestro\Entity\MaestroProcess; use Drupal\webform\Entity\WebformSubmission; +use Psr\Log\LoggerInterface; /** * Class ForloebTaskConsole. */ class ForloebTaskConsole { + use StringTranslationTrait; + /** * Drupal\Core\Entity\EntityTypeManagerInterface definition. * @@ -19,13 +23,22 @@ class ForloebTaskConsole { */ protected $entityTypeManager; + /** + * Logger. + * + * @var \Psr\Log\LoggerInterface + */ + protected $logger; + /** * Constructs a new ForloebTaskConsole object. */ - public function __construct(EntityTypeManagerInterface $entity_type_manager) { + public function __construct(EntityTypeManagerInterface $entity_type_manager, LoggerInterface $logger) { $this->entityTypeManager = $entity_type_manager; + $this->logger = $logger; } + /** * Gets MaestroQueue record by webforms submission token. * @@ -40,47 +53,30 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager) { public function getQueueIdByWebformSubmissionToken($token = '') { /** @var WebformSubmission $webform_submission */ $webform_submissions = $this->entityTypeManager->getStorage('webform_submission')->loadByProperties(['token' => $token]); + + if (empty($webform_submissions)) { + $this->logger->warning($this->t('Submission with token @token not found', ['@token' => $token])); + return NULL; + } + $webform_submission = reset($webform_submissions); /** @var MaestroEntityIdentifiers $maestro_entity_identifier */ - $maestro_entity_identifiers = $this->entityTypeManager->getStorage('maestro_entity_identifiers')->loadByProperties([ - 'entity_type' => 'webform_submission', - 'entity_id' => $webform_submission->id(), - ]); + $maestro_entity_identifiers = $this->entityTypeManager->getStorage('maestro_entity_identifiers')->loadByProperties(['entity_type' => 'webform_submission', 'entity_id' => $webform_submission->id(),]); $maestro_entity_identifier = reset($maestro_entity_identifiers); $processIDs = $maestro_entity_identifier->process_id->referencedEntities(); + if (empty($processIDs)) { + $this->logger->warning($this->t('Process with entity type: webform_submission and entity_id: @entity_id not found', ['@entity_id' => $webform_submission->id()])); + return NULL; + } + $processID = reset($processIDs); - $maestro_queues = $this->entityTypeManager->getStorage('maestro_queue')->loadByProperties([ - 'process_id' => $processID->id(), - 'task_class_name' => 'MaestroWebformInherit', - ]); + $maestro_queues = $this->entityTypeManager->getStorage('maestro_queue')->loadByProperties(['process_id' => $processID->id(), 'task_class_name' => 'MaestroWebformInherit',]); + if (empty($maestro_queues)) { + $this->logger->warning($this->t('Maestro queue with task_class_name: MaestroWebformInherit and process_id: @process_id not found', ['@process_id' => $processID->id()])); + return NULL; + } $maestro_queue = reset($maestro_queues); return $maestro_queue; - - $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; - - // Compare webform submission with token from request. - if ($webform_submission && $webform_submission->getToken() == $token) { - return $queueRecord; - } - } - - return NULL; } + } diff --git a/src/Plugin/EngineTasks/MaestroWebformInheritTask.php b/src/Plugin/EngineTasks/MaestroWebformInheritTask.php index e0bad7c..c9655b8 100644 --- a/src/Plugin/EngineTasks/MaestroWebformInheritTask.php +++ b/src/Plugin/EngineTasks/MaestroWebformInheritTask.php @@ -2,6 +2,7 @@ namespace Drupal\os2forms_forloeb\Plugin\EngineTasks; +use Drupal\Core\Url; use Drupal\webform\Entity\WebformSubmission; use Drupal\webform\WebformSubmissionForm; use Drupal\maestro_webform\Plugin\EngineTasks\MaestroWebformTask; @@ -12,6 +13,7 @@ use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\Messenger; +use Symfony\Component\HttpFoundation\RedirectResponse; /** * Maestro Webform Task Plugin for Multiple Submissions. @@ -83,7 +85,7 @@ public function getTaskEditForm(array $task, $templateMachineName) { * {@inheritDoc} */ public function prepareTaskForSave(array &$form, FormStateInterface $form_state, array &$task) { - + // Inherit from parent parent::prepareTaskForSave($form, $form_state, $task); // Add custom field(s) to the inherited prepareTaskForSave method. @@ -102,7 +104,7 @@ public function getExecutableForm($modal, MaestroExecuteInteractive $parent) { // Get user input from 'inherit_webform_unique_id' $webformInheritID = $task['data']['inherit_webform_unique_id']; - + // Load its corresponding webform submission. $sid = MaestroEngine::getEntityIdentiferByUniqueID($this->processID, $webformInheritID); if ($sid) { @@ -151,6 +153,17 @@ public function getExecutableForm($modal, MaestroExecuteInteractive $parent) { $new_submission->bundle(), $taskUniqueSubmissionId, $sid ); - return parent::getExecutableForm($modal, $parent); + $form = parent::getExecutableForm($modal, $parent); + // Catch os2forms-forloeb access token and pass it further. + if ($form instanceof RedirectResponse && $token = \Drupal::request()->query->get('os2forms-forloeb-ws-token')) { + // Check token to previous submission and update it to new one. + if ($token == $webform_submission->getToken()) { + $token = $new_submission->getToken(); + $url = Url::fromUserInput($form->getTargetUrl(), ['query' => ['os2forms-forloeb-ws-token' => $token]]); + $form = new RedirectResponse($url->toString()); + } + } + + return $form; } } From bcf38f833ca856d340684b1932399e1f310ad22d Mon Sep 17 00:00:00 2001 From: andriyun Date: Tue, 17 May 2022 14:51:21 +0200 Subject: [PATCH 4/4] OS2FORMS-371 Review fixes --- os2forms_forloeb.module | 2 +- src/Plugin/EngineTasks/MaestroWebformInheritTask.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/os2forms_forloeb.module b/os2forms_forloeb.module index 125f4a4..155fcf9 100644 --- a/os2forms_forloeb.module +++ b/os2forms_forloeb.module @@ -308,7 +308,7 @@ function os2forms_forloeb_tokens($type, array $tokens, array $data, array $optio function os2forms_forloeb_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account) { if ($operation == 'update' && $entity instanceof WebformSubmission) { $token = \Drupal::request()->query->get('os2forms-forloeb-ws-token'); - if ($token && $token == $entity->getToken()) { + if ($token && $token === $entity->getToken()) { return \Drupal\Core\Access\AccessResult::allowed(); } } diff --git a/src/Plugin/EngineTasks/MaestroWebformInheritTask.php b/src/Plugin/EngineTasks/MaestroWebformInheritTask.php index c9655b8..ecdceaf 100644 --- a/src/Plugin/EngineTasks/MaestroWebformInheritTask.php +++ b/src/Plugin/EngineTasks/MaestroWebformInheritTask.php @@ -157,7 +157,7 @@ public function getExecutableForm($modal, MaestroExecuteInteractive $parent) { // Catch os2forms-forloeb access token and pass it further. if ($form instanceof RedirectResponse && $token = \Drupal::request()->query->get('os2forms-forloeb-ws-token')) { // Check token to previous submission and update it to new one. - if ($token == $webform_submission->getToken()) { + if ($token === $webform_submission->getToken()) { $token = $new_submission->getToken(); $url = Url::fromUserInput($form->getTargetUrl(), ['query' => ['os2forms-forloeb-ws-token' => $token]]); $form = new RedirectResponse($url->toString());