From de9a7a1f1f74d78731838d62983facf4b55e143e Mon Sep 17 00:00:00 2001 From: Mikkel Ricky Date: Wed, 11 Mar 2026 09:49:03 +0100 Subject: [PATCH 1/8] =?UTF-8?q?Added=20=E2=80=9CDisplay=20on=E2=80=9C=20op?= =?UTF-8?q?tions=20to=20Map=20element?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/os2forms_webform_maps/README.md | 6 + .../os2forms_webform_maps.module | 44 ------- .../WebformElement/WebformLeafletMapField.php | 109 ++++++++++++++++++ ...ent-base-html--webform-map-field.html.twig | 18 --- 4 files changed, 115 insertions(+), 62 deletions(-) delete mode 100644 modules/os2forms_webform_maps/templates/webform-element-base-html--webform-map-field.html.twig diff --git a/modules/os2forms_webform_maps/README.md b/modules/os2forms_webform_maps/README.md index c36b901e..1fee0ea2 100644 --- a/modules/os2forms_webform_maps/README.md +++ b/modules/os2forms_webform_maps/README.md @@ -14,3 +14,9 @@ the map. The data can be exported to PDF. ## Installation The module can be installed using the standard Drupal installation procedure. + +## Fetching GeoJSON using the API + +``` shell +@todo +``` diff --git a/modules/os2forms_webform_maps/os2forms_webform_maps.module b/modules/os2forms_webform_maps/os2forms_webform_maps.module index af545a5d..17d33aab 100644 --- a/modules/os2forms_webform_maps/os2forms_webform_maps.module +++ b/modules/os2forms_webform_maps/os2forms_webform_maps.module @@ -5,22 +5,6 @@ * Module file for os2forms_webform_maps. */ -/** - * Implements hook_theme(). - */ -function os2forms_webform_maps_theme() { - return [ - 'webform_element_base_html__webform_map_field' => [ - 'variables' => [ - 'element' => [], - 'value' => NULL, - 'webform_submission' => NULL, - 'options' => [], - ], - ], - ]; -} - /** * Implements hook_locale_translation_projects_alter(). */ @@ -29,31 +13,3 @@ function os2forms_webform_maps_locale_translation_projects_alter(&$projects) { $path = $module_handler->getModule('os2forms_webform_maps')->getPath(); $projects['os2forms_webform_maps']['info']['interface translation server pattern'] = $path . '/translations/%language.po'; } - -/** - * Implements hook_preprocess_webform_element_base_html__webform_map_field(). - */ -function os2forms_webform_maps_preprocess_webform_element_base_html__webform_map_field(array &$variables) { - // Decode the plain text value once. - $decoded_value = json_decode($variables['value']['#plain_text']); - - // Use the decoded geojson property. - $variables['value']['#plain_text'] = $decoded_value->geojson; - - // Load the webform element base HTML template. - \Drupal::moduleHandler()->loadInclude('webform', 'inc', 'includes/webform.theme.template'); - template_preprocess_webform_element_base_html($variables); - - // Generate a unique ID for the map image. - $map_image_id = 'map-image-' . $variables['element']['#webform_key']; - - $variables['map_image'] = [ - '#type' => 'html_tag', - '#tag' => 'img', - '#attributes' => [ - 'class' => ['handler-help-message'], - 'id' => [$map_image_id], - 'src' => $decoded_value->image ?? '', - ], - ]; -} diff --git a/modules/os2forms_webform_maps/src/Plugin/WebformElement/WebformLeafletMapField.php b/modules/os2forms_webform_maps/src/Plugin/WebformElement/WebformLeafletMapField.php index 3b6aa405..f0619e56 100644 --- a/modules/os2forms_webform_maps/src/Plugin/WebformElement/WebformLeafletMapField.php +++ b/modules/os2forms_webform_maps/src/Plugin/WebformElement/WebformLeafletMapField.php @@ -5,6 +5,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\leaflet\LeafletSettingsElementsTrait; use Drupal\webform\Plugin\WebformElementBase; +use Drupal\webform\WebformSubmissionInterface; /** * Provides a 'webform_map_field' element. @@ -70,6 +71,10 @@ public function defineDefaultProperties(): array { 'circle_color' => '#3388FF', 'rectangle_color' => '#3388FF', + // Display settings. + 'display_image_on' => ['html', 'pdf'], + 'display_geojson_on' => ['text', 'html'], + ] + parent::defineDefaultProperties(); } @@ -344,7 +349,111 @@ public function form(array $form, FormStateInterface $form_state) { ], ]; + $form['display_settings'] = [ + '#type' => 'fieldset', + '#title' => $this->t('Display settings'), + ]; + $form['display_settings']['display_settings_container'] = [ + 'display_image_on' => [ + '#type' => 'checkboxes', + '#title' => $this->t('Display image on'), + '#options' => [ + 'html' => $this->t('HTML'), + 'pdf' => $this->t('PDF'), + ], + ], + + 'display_geojson_on' => [ + '#type' => 'checkboxes', + '#title' => $this->t('Display GeoJSON on'), + '#options' => [ + 'html' => $this->t('HTML'), + 'pdf' => $this->t('PDF'), + 'text' => $this->t('Text'), + ], + ], + ]; + return $form; } + /** + * {@inheritdoc} + */ + protected function formatHtmlItem(array $element, WebformSubmissionInterface $webform_submission, array $options = []): array { + $value = $this->getMapValue($element, $webform_submission, $options); + + $imageId = 'map-image-' . $this->getKey($element); + + $build = []; + + $viewMode = $options['view_mode'] ?? 'overview'; + if ('table' === $viewMode) { + $viewMode = 'html'; + } + if ('html' === $viewMode && $options['pdf']) { + $viewMode = 'pdf'; + } + + // @todo Is this (i.e. $element['#display_image_on']) really the way to get element configuration? + $showImageOn = array_filter((array) ($element['#display_image_on'] ?? NULL)); + $includeImage = isset($showImageOn[$viewMode]); + + $showGeoJsonOn = array_filter((array) ($element['#display_geojson_on'] ?? NULL)); + $includeGeoJson = isset($showGeoJsonOn[$viewMode]); + + if ($includeImage) { + $build['image'] = [ + '#type' => 'html_tag', + '#tag' => 'img', + '#attributes' => [ + 'class' => ['handler-help-message'], + 'id' => $imageId, + 'src' => $value['image'], + ], + ]; + } + + if ($includeGeoJson) { + $build['geojson'] = [ + '#markup' => $value['geojson'], + ]; + } + + return $build; + } + + /** + * {@inheritdoc} + */ + protected function formatTextItem(array $element, WebformSubmissionInterface $webform_submission, array $options = []) { + $value = $this->getMapValue($element, $webform_submission, $options); + + return $value['geojson']; + } + + /** + * Get structured map value. + * + * @return array{ + * image: string, + * geojson: string + * } + */ + private function getMapValue(array $element, WebformSubmissionInterface $webform_submission, array $options = []): array { + $value = $this->getValue($element, $webform_submission, $options); + + try { + $data = json_decode($value, associative: TRUE, flags: JSON_THROW_ON_ERROR); + } + catch (\JsonException) { + $data = []; + } + + return $data + [ + 'image' => '', + 'geojson' => 'null', + ]; + } + } diff --git a/modules/os2forms_webform_maps/templates/webform-element-base-html--webform-map-field.html.twig b/modules/os2forms_webform_maps/templates/webform-element-base-html--webform-map-field.html.twig deleted file mode 100644 index cd3a19bd..00000000 --- a/modules/os2forms_webform_maps/templates/webform-element-base-html--webform-map-field.html.twig +++ /dev/null @@ -1,18 +0,0 @@ -{# -/** - * @file - * Default theme implementation for a webform base element as html. - * - * Available variables: - * - element: The element. - * - title: The label for the element. - * - value: The content for the element. - * - item: The form item used to display the element. - * - options Associative array of options for element. - * - multiline: Flag to determine if value spans multiple lines. - * - email: Flag to determine if element is for an email. - */ -#} - {{ map_image }} - {{ item }} - From 7c5e04ea4a249c564a7d6a524c557f66be271dc0 Mon Sep 17 00:00:00 2001 From: Mikkel Ricky Date: Wed, 11 Mar 2026 10:42:26 +0100 Subject: [PATCH 2/8] Added documentation on fetching GeoJSON using the API --- modules/os2forms_webform_maps/README.md | 53 ++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/modules/os2forms_webform_maps/README.md b/modules/os2forms_webform_maps/README.md index 1fee0ea2..6c9e6300 100644 --- a/modules/os2forms_webform_maps/README.md +++ b/modules/os2forms_webform_maps/README.md @@ -17,6 +17,55 @@ The module can be installed using the standard Drupal installation procedure. ## Fetching GeoJSON using the API -``` shell -@todo +Assume that we have a webform with ID `my_webform` and the webform has a Map element with ID `my_map`. We can then fetch +the data for a submission with UUID `c34d01c5-7bd9-4b15-8b01-5787959453c0` on the webform with a HTTP `GET` request (cf. +[OS2Forms REST API](https://github.com/itk-dev/os2forms_rest_api/blob/main/README.md)): + +``` shell name=api-fetch-submission-data +curl --silent --location --header 'api-key: my-api-key' http://127.0.0.1:8000/webform_rest/my_webform/submission/c34d01c5-7bd9-4b15-8b01-5787959453c0 +# {"entity":{"serial":[{"value":1}],"sid":[{"value":2}],"uuid":[{"value":"c34d01c5-7bd9-4b15-8b01-5787959453c0"}],…``` +``` + +The result, however, contains a lot of data and we need a little more work the extract just the GeoJSON data. + +Using [`jq`](https://jqlang.org/) (or similar tools), we can drill down into the full submission data to extract just +the GeoJSON data from the Map element (JSON decoding twice along the way): + +``` shell name=api-extract-map-element-data +curl --silent --location --header 'api-key: my-api-key' http://127.0.0.1:8000/webform_rest/my_webform/submission/c34d01c5-7bd9-4b15-8b01-5787959453c0 | jq '.data.my_map | fromjson | .geojson | fromjson' +``` + +The final result will be something like + +``` json +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + 10.193674, + 56.158929 + ], + [ + 10.241758, + 56.155296 + ], + [ + 10.242788, + 56.130048 + ], + [ + 10.189209, + 56.129283 + ] + ] + } + } + ] +} ``` From ff515e3c4416480e31744535c3619a1e831d4b0f Mon Sep 17 00:00:00 2001 From: Mikkel Ricky Date: Wed, 11 Mar 2026 10:45:15 +0100 Subject: [PATCH 3/8] Updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fabc6c1..075e7d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ before starting to add changes. Use example [placed in the end of the page](#exa ## [Unreleased] +- [PR-315](https://github.com/OS2Forms/os2forms/pull/315) + Added “Display on“ options to Map element - [#251](https://github.com/OS2Forms/os2forms/issues/251) Webform encrypt uninstall problem fix - git actions check From 3c9dffb1c3e7cd17e27b6d0a91cac8da5b44341e Mon Sep 17 00:00:00 2001 From: Mikkel Ricky Date: Wed, 11 Mar 2026 12:40:14 +0100 Subject: [PATCH 4/8] Handled "mail" display --- .../WebformElement/WebformLeafletMapField.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/os2forms_webform_maps/src/Plugin/WebformElement/WebformLeafletMapField.php b/modules/os2forms_webform_maps/src/Plugin/WebformElement/WebformLeafletMapField.php index f0619e56..00327dcf 100644 --- a/modules/os2forms_webform_maps/src/Plugin/WebformElement/WebformLeafletMapField.php +++ b/modules/os2forms_webform_maps/src/Plugin/WebformElement/WebformLeafletMapField.php @@ -72,9 +72,8 @@ public function defineDefaultProperties(): array { 'rectangle_color' => '#3388FF', // Display settings. - 'display_image_on' => ['html', 'pdf'], + 'display_image_on' => ['email', 'html', 'pdf'], 'display_geojson_on' => ['text', 'html'], - ] + parent::defineDefaultProperties(); } @@ -358,6 +357,7 @@ public function form(array $form, FormStateInterface $form_state) { '#type' => 'checkboxes', '#title' => $this->t('Display image on'), '#options' => [ + 'email' => $this->t('Email'), 'html' => $this->t('HTML'), 'pdf' => $this->t('PDF'), ], @@ -367,6 +367,7 @@ public function form(array $form, FormStateInterface $form_state) { '#type' => 'checkboxes', '#title' => $this->t('Display GeoJSON on'), '#options' => [ + 'email' => $this->t('Email'), 'html' => $this->t('HTML'), 'pdf' => $this->t('PDF'), 'text' => $this->t('Text'), @@ -387,11 +388,14 @@ protected function formatHtmlItem(array $element, WebformSubmissionInterface $we $build = []; - $viewMode = $options['view_mode'] ?? 'overview'; + $viewMode = $options['view_mode'] ?? 'results'; if ('table' === $viewMode) { $viewMode = 'html'; } - if ('html' === $viewMode && $options['pdf']) { + elseif ($options['email'] ?? FALSE) { + $viewMode = 'email'; + } + elseif ($options['pdf'] ?? FALSE) { $viewMode = 'pdf'; } @@ -411,12 +415,16 @@ protected function formatHtmlItem(array $element, WebformSubmissionInterface $we 'id' => $imageId, 'src' => $value['image'], ], + '#prefix' => '
', + '#suffix' => '
', ]; } if ($includeGeoJson) { $build['geojson'] = [ '#markup' => $value['geojson'], + '#prefix' => '
', + '#suffix' => '
', ]; } From 31f4ca5c1725e878bd9f4072159db188025604d1 Mon Sep 17 00:00:00 2001 From: Mikkel Ricky Date: Thu, 12 Mar 2026 09:57:42 +0100 Subject: [PATCH 5/8] Updated URL --- modules/os2forms_webform_maps/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/os2forms_webform_maps/README.md b/modules/os2forms_webform_maps/README.md index 6c9e6300..d93aa5d4 100644 --- a/modules/os2forms_webform_maps/README.md +++ b/modules/os2forms_webform_maps/README.md @@ -19,7 +19,7 @@ The module can be installed using the standard Drupal installation procedure. Assume that we have a webform with ID `my_webform` and the webform has a Map element with ID `my_map`. We can then fetch the data for a submission with UUID `c34d01c5-7bd9-4b15-8b01-5787959453c0` on the webform with a HTTP `GET` request (cf. -[OS2Forms REST API](https://github.com/itk-dev/os2forms_rest_api/blob/main/README.md)): +[OS2Forms REST API](https://github.com/OS2Forms/os2forms_rest_api/blob/main/README.md)): ``` shell name=api-fetch-submission-data curl --silent --location --header 'api-key: my-api-key' http://127.0.0.1:8000/webform_rest/my_webform/submission/c34d01c5-7bd9-4b15-8b01-5787959453c0 From 9680ac4491346e86a17d08dd74c8abde31e2ec72 Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Tue, 9 Jun 2026 14:43:37 +0200 Subject: [PATCH 6/8] Release 5.1.0 and feature/maps-element-display --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d3a1ba7..118a8e55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ before starting to add changes. Use example [placed in the end of the page](#exa - [PR-315](https://github.com/OS2Forms/os2forms/pull/315) Added “Display on“ options to Map element + +## [5.1.0] + - [PR-326](https://github.com/OS2Forms/os2forms/pull/326) Updating ckeditor -> ckeditor5. - [PR-322](https://github.com/OS2Forms/os2forms/pull/322) From 70fe8d34463b36ae577a7bdb7aaaf1b82d3918e6 Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Tue, 23 Jun 2026 14:02:58 +0200 Subject: [PATCH 7/8] Allow configurating on which submission states handlers should run --- CHANGELOG.md | 8 ++ .../os2forms_digital_post.install | 32 ++++++++ .../WebformHandler/WebformHandlerSF1601.php | 41 ++++++++++ .../os2forms_digital_signature.install | 39 ++++++++++ .../DigitalSignatureWebformHandler.php | 74 ++++++++++++++++++- modules/os2forms_fasit/os2forms_fasit.install | 33 +++++++++ .../WebformHandler/FasitWebformHandler.php | 51 +++++++++++++ .../os2forms_fbs_handler.install | 39 ++++++++++ .../WebformHandler/FbsWebformHandler.php | 51 +++++++++++++ 9 files changed, 365 insertions(+), 3 deletions(-) create mode 100644 modules/os2forms_digital_signature/os2forms_digital_signature.install create mode 100644 modules/os2forms_fbs_handler/os2forms_fbs_handler.install diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ddc05ab..e57aca61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,14 @@ before starting to add changes. Use example [placed in the end of the page](#exa ## [Unreleased] +- Added the ability to configure on which submission states handlers should run. + The default option is to run on the completed state. Changes was made to the + following handlers: + - Digital post + - Fasit + - FBS + - Digital signature + ## [5.1.0] 2026-06-03 - [PR-326](https://github.com/OS2Forms/os2forms/pull/326) diff --git a/modules/os2forms_digital_post/os2forms_digital_post.install b/modules/os2forms_digital_post/os2forms_digital_post.install index 48768e21..cb410b1d 100644 --- a/modules/os2forms_digital_post/os2forms_digital_post.install +++ b/modules/os2forms_digital_post/os2forms_digital_post.install @@ -6,6 +6,7 @@ */ use Drupal\os2forms_digital_post\Helper\BeskedfordelerHelper; +use Drupal\webform\WebformSubmissionInterface; /** * Implements hook_schema(). @@ -26,3 +27,34 @@ function os2forms_digital_post_update_9001(): void { 'os2web_key', ], TRUE); } + +/** + * Set states config to completed on existing digital post handlers. + */ +function os2forms_digital_post_update_10001(): void { + // To avoid having to load full webforms we load and update webform configs. + $configFactory = \Drupal::configFactory(); + + foreach ($configFactory->listAll('webform.webform.') as $name) { + $config = $configFactory->getEditable($name); + $handlers = $config->get('handlers'); + if (!is_array($handlers)) { + continue; + } + + $changed = FALSE; + + foreach ($handlers as $handlerKey => $handler) { + // $handler['id'] is the handler plugin id. + if (($handler['id'] ?? NULL) !== 'digital_post_sf1601') { + continue; + } + $handlers[$handlerKey]['settings']['additional']['states'] = [WebformSubmissionInterface::STATE_COMPLETED]; + $changed = TRUE; + } + + if ($changed) { + $config->set('handlers', $handlers)->save(); + } + } +} diff --git a/modules/os2forms_digital_post/src/Plugin/WebformHandler/WebformHandlerSF1601.php b/modules/os2forms_digital_post/src/Plugin/WebformHandler/WebformHandlerSF1601.php index 6f0e06a9..ae633c01 100644 --- a/modules/os2forms_digital_post/src/Plugin/WebformHandler/WebformHandlerSF1601.php +++ b/modules/os2forms_digital_post/src/Plugin/WebformHandler/WebformHandlerSF1601.php @@ -32,6 +32,8 @@ final class WebformHandlerSF1601 extends WebformHandlerBase { public const RECIPIENT_ELEMENT = 'recipient_element'; public const ATTACHMENT_ELEMENT = 'attachment_element'; public const SENDER_ADDRESS = 'sender_address'; + private const string ADDITIONAL = 'additional'; + private const string STATES = 'states'; /** * Maximum length of sender label. @@ -76,6 +78,9 @@ public static function create(ContainerInterface $container, array $configuratio public function defaultConfiguration() { return [ 'debug' => FALSE, + self::ADDITIONAL => [ + self::STATES => [WebformSubmissionInterface::STATE_COMPLETED], + ], ]; } @@ -203,6 +208,31 @@ public function buildConfigurationForm(array $form, FormStateInterface $formStat '#default_value' => $this->configuration['debug'] ?? NULL, ]; + // Additional. + // Lifted from EmailWebformHandler::buildConfigurationForm(). + $resultsDisabled = (bool) $this->getWebform()->getSetting('results_disabled'); + $form[self::ADDITIONAL] = [ + '#type' => 'fieldset', + '#title' => $this->t('Additional settings'), + ]; + // Settings: States. + $states = (array) ($this->configuration[self::ADDITIONAL][self::STATES] ?? NULL); + $form[self::ADDITIONAL][self::STATES] = [ + '#type' => 'checkboxes', + '#title' => $this->t('Run handler when …'), + '#options' => [ + WebformSubmissionInterface::STATE_DRAFT_CREATED => $this->t('draft is created.'), + WebformSubmissionInterface::STATE_DRAFT_UPDATED => $this->t('draft is updated.'), + WebformSubmissionInterface::STATE_CONVERTED => $this->t('anonymous submission is converted to authenticated.'), + WebformSubmissionInterface::STATE_COMPLETED => $this->t('submission is completed.'), + WebformSubmissionInterface::STATE_UPDATED => $this->t('submission is updated.'), + WebformSubmissionInterface::STATE_DELETED => $this->t('submission is deleted.'), + WebformSubmissionInterface::STATE_LOCKED => $this->t('submission is locked.'), + ], + '#access' => !$resultsDisabled, + '#default_value' => $resultsDisabled ? [WebformSubmissionInterface::STATE_COMPLETED] : $states, + ]; + return $this->setSettingsParents($form); } @@ -333,6 +363,11 @@ static function (array $action) { $this->configuration[self::MEMO_ACTIONS] = $actions; $this->configuration['debug'] = (bool) $formState->getValue('debug'); + + $additional = $formState->getValue(self::ADDITIONAL); + // Clean up states. + $additional[self::STATES] = array_values(array_filter($additional[self::STATES])); + $this->configuration[self::ADDITIONAL] = $additional; } /** @@ -341,6 +376,12 @@ static function (array $action) { * @phpstan-return void */ public function postSave(WebformSubmissionInterface $webformSubmission, $update = TRUE) { + $submissionState = $webformSubmission->getWebform()->getSetting('results_disabled') ? WebformSubmissionInterface::STATE_COMPLETED : $webformSubmission->getState(); + $enabledStates = (array) ($this->configuration[self::ADDITIONAL][self::STATES] ?? NULL); + if (!in_array($submissionState, $enabledStates)) { + return; + } + $this->helper->createJob($webformSubmission, $this->configuration); } diff --git a/modules/os2forms_digital_signature/os2forms_digital_signature.install b/modules/os2forms_digital_signature/os2forms_digital_signature.install new file mode 100644 index 00000000..4e5cb76a --- /dev/null +++ b/modules/os2forms_digital_signature/os2forms_digital_signature.install @@ -0,0 +1,39 @@ +listAll('webform.webform.') as $name) { + $config = $configFactory->getEditable($name); + $handlers = $config->get('handlers'); + if (!is_array($handlers)) { + continue; + } + + $changed = FALSE; + + foreach ($handlers as $handlerKey => $handler) { + // $handler['id'] is the handler plugin id. + if (($handler['id'] ?? NULL) !== 'os2forms_digital_signature') { + continue; + } + $handlers[$handlerKey]['settings']['additional']['states'] = [WebformSubmissionInterface::STATE_COMPLETED]; + $changed = TRUE; + } + + if ($changed) { + $config->set('handlers', $handlers)->save(); + } + } +} diff --git a/modules/os2forms_digital_signature/src/Plugin/WebformHandler/DigitalSignatureWebformHandler.php b/modules/os2forms_digital_signature/src/Plugin/WebformHandler/DigitalSignatureWebformHandler.php index 9a616bfc..78252c00 100644 --- a/modules/os2forms_digital_signature/src/Plugin/WebformHandler/DigitalSignatureWebformHandler.php +++ b/modules/os2forms_digital_signature/src/Plugin/WebformHandler/DigitalSignatureWebformHandler.php @@ -7,6 +7,7 @@ use Drupal\Core\File\FileExists; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\File\FileUrlGeneratorInterface; +use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Site\Settings; use Drupal\Core\Url; use Drupal\file\FileRepositoryInterface; @@ -88,6 +89,9 @@ class DigitalSignatureWebformHandler extends WebformHandlerBase { */ private readonly Settings $settings; + private const string ADDITIONAL = 'additional'; + private const string STATES = 'states'; + /** * {@inheritdoc} */ @@ -107,14 +111,78 @@ public static function create(ContainerInterface $container, array $configuratio /** * {@inheritdoc} + * + * @phpstan-return array */ - public function preSave(WebformSubmissionInterface $webform_submission) { - $webform = $webform_submission->getWebform(); + public function defaultConfiguration() { + return [ + self::ADDITIONAL => [ + self::STATES => [WebformSubmissionInterface::STATE_COMPLETED], + ], + ]; + } + + /** + * {@inheritdoc} + * + * @phpstan-param array $form + * @phpstan-return array + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + // Additional. + // Lifted from EmailWebformHandler::buildConfigurationForm(). + $resultsDisabled = (bool) $this->getWebform()->getSetting('results_disabled'); + $form[self::ADDITIONAL] = [ + '#type' => 'fieldset', + '#title' => $this->t('Additional settings'), + ]; + // Settings: States. + $states = (array) ($this->configuration[self::ADDITIONAL][self::STATES] ?? NULL); + $form[self::ADDITIONAL][self::STATES] = [ + '#type' => 'checkboxes', + '#title' => $this->t('Run handler when …'), + '#options' => [ + WebformSubmissionInterface::STATE_DRAFT_CREATED => $this->t('draft is created.'), + WebformSubmissionInterface::STATE_DRAFT_UPDATED => $this->t('draft is updated.'), + WebformSubmissionInterface::STATE_CONVERTED => $this->t('anonymous submission is converted to authenticated.'), + WebformSubmissionInterface::STATE_COMPLETED => $this->t('submission is completed.'), + WebformSubmissionInterface::STATE_UPDATED => $this->t('submission is updated.'), + WebformSubmissionInterface::STATE_DELETED => $this->t('submission is deleted.'), + // The digital signature logic locks after the first signing. Resigning + // does not make sense, so 'locked' is not an option here. + ], + '#access' => !$resultsDisabled, + '#default_value' => $resultsDisabled ? [WebformSubmissionInterface::STATE_COMPLETED] : $states, + ]; + + return $this->setSettingsParents($form); + } - if ($webform_submission->isLocked()) { + /** + * {@inheritdoc} + * + * @phpstan-param array $form + * @phpstan-return void + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + $additional = $form_state->getValue(self::ADDITIONAL); + // Clean up states. + $additional[self::STATES] = array_values(array_filter($additional[self::STATES])); + $this->configuration[self::ADDITIONAL] = $additional; + } + + /** + * {@inheritdoc} + */ + public function preSave(WebformSubmissionInterface $webform_submission) { + $submissionState = $webform_submission->getWebform()->getSetting('results_disabled') ? WebformSubmissionInterface::STATE_COMPLETED : $webform_submission->getState(); + $enabledStates = (array) ($this->configuration[self::ADDITIONAL][self::STATES] ?? NULL); + if (!in_array($submissionState, $enabledStates)) { return; } + $webform = $webform_submission->getWebform(); + $attachment = $this->getSubmissionAttachment($webform_submission); if (!$attachment) { $this->logger->error('Attachment cannot be created webform: %webform, webform_submission: %webform_submission', diff --git a/modules/os2forms_fasit/os2forms_fasit.install b/modules/os2forms_fasit/os2forms_fasit.install index f862bafb..8d471f49 100644 --- a/modules/os2forms_fasit/os2forms_fasit.install +++ b/modules/os2forms_fasit/os2forms_fasit.install @@ -5,6 +5,8 @@ * Install hooks for os2forms_fasit. */ +use Drupal\webform\WebformSubmissionInterface; + /** * Install Key module. */ @@ -13,3 +15,34 @@ function os2forms_fasit_update_9001(): void { 'key', ], TRUE); } + +/** + * Set states config to completed on existing fasit handlers. + */ +function os2forms_fasit_update_10001(): void { + // To avoid having to load full webforms we load and update webform configs. + $configFactory = \Drupal::configFactory(); + + foreach ($configFactory->listAll('webform.webform.') as $name) { + $config = $configFactory->getEditable($name); + $handlers = $config->get('handlers'); + if (!is_array($handlers)) { + continue; + } + + $changed = FALSE; + + foreach ($handlers as $handlerKey => $handler) { + // $handler['id'] is the handler plugin id. + if (($handler['id'] ?? NULL) !== 'os2forms_fasit') { + continue; + } + $handlers[$handlerKey]['settings']['additional']['states'] = [WebformSubmissionInterface::STATE_COMPLETED]; + $changed = TRUE; + } + + if ($changed) { + $config->set('handlers', $handlers)->save(); + } + } +} diff --git a/modules/os2forms_fasit/src/Plugin/WebformHandler/FasitWebformHandler.php b/modules/os2forms_fasit/src/Plugin/WebformHandler/FasitWebformHandler.php index 84eef379..e726bf44 100644 --- a/modules/os2forms_fasit/src/Plugin/WebformHandler/FasitWebformHandler.php +++ b/modules/os2forms_fasit/src/Plugin/WebformHandler/FasitWebformHandler.php @@ -35,6 +35,8 @@ class FasitWebformHandler extends WebformHandlerBase { public const FASIT_HANDLER_DOCUMENT_DESCRIPTION = 'document_description'; public const FASIT_HANDLER_CPR_ELEMENT = 'cpr_element'; public const FASIT_HANDLER_ATTACHMENT_ELEMENT = 'attachment_element'; + private const string ADDITIONAL = 'additional'; + private const string STATES = 'states'; /** * The submission logger. @@ -79,6 +81,19 @@ public static function create(ContainerInterface $container, array $configuratio ); } + /** + * {@inheritdoc} + * + * @phpstan-return array + */ + public function defaultConfiguration() { + return [ + self::ADDITIONAL => [ + self::STATES => [WebformSubmissionInterface::STATE_COMPLETED], + ], + ]; + } + /** * {@inheritdoc} * @@ -129,6 +144,31 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#size' => 5, ]; + // Additional. + // Lifted from EmailWebformHandler::buildConfigurationForm(). + $resultsDisabled = (bool) $this->getWebform()->getSetting('results_disabled'); + $form[self::ADDITIONAL] = [ + '#type' => 'fieldset', + '#title' => $this->t('Additional settings'), + ]; + // Settings: States. + $states = (array) ($this->configuration[self::ADDITIONAL][self::STATES] ?? NULL); + $form[self::ADDITIONAL][self::STATES] = [ + '#type' => 'checkboxes', + '#title' => $this->t('Run handler when …'), + '#options' => [ + WebformSubmissionInterface::STATE_DRAFT_CREATED => $this->t('draft is created.'), + WebformSubmissionInterface::STATE_DRAFT_UPDATED => $this->t('draft is updated.'), + WebformSubmissionInterface::STATE_CONVERTED => $this->t('anonymous submission is converted to authenticated.'), + WebformSubmissionInterface::STATE_COMPLETED => $this->t('submission is completed.'), + WebformSubmissionInterface::STATE_UPDATED => $this->t('submission is updated.'), + WebformSubmissionInterface::STATE_DELETED => $this->t('submission is deleted.'), + WebformSubmissionInterface::STATE_LOCKED => $this->t('submission is locked.'), + ], + '#access' => !$resultsDisabled, + '#default_value' => $resultsDisabled ? [WebformSubmissionInterface::STATE_COMPLETED] : $states, + ]; + return $this->setSettingsParents($form); } @@ -143,12 +183,23 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s $this->configuration[self::FASIT_HANDLER_GENERAL][self::FASIT_HANDLER_DOCUMENT_DESCRIPTION] = $form_state->getValue(self::FASIT_HANDLER_GENERAL)[self::FASIT_HANDLER_DOCUMENT_DESCRIPTION]; $this->configuration[self::FASIT_HANDLER_GENERAL][self::FASIT_HANDLER_CPR_ELEMENT] = $form_state->getValue(self::FASIT_HANDLER_GENERAL)[self::FASIT_HANDLER_CPR_ELEMENT]; $this->configuration[self::FASIT_HANDLER_GENERAL][self::FASIT_HANDLER_ATTACHMENT_ELEMENT] = $form_state->getValue(self::FASIT_HANDLER_GENERAL)[self::FASIT_HANDLER_ATTACHMENT_ELEMENT]; + + $additional = $form_state->getValue(self::ADDITIONAL); + // Clean up states. + $additional[self::STATES] = array_values(array_filter($additional[self::STATES])); + $this->configuration[self::ADDITIONAL] = $additional; } /** * {@inheritdoc} */ public function postSave(WebformSubmissionInterface $webform_submission, $update = TRUE): void { + $submissionState = $webform_submission->getWebform()->getSetting('results_disabled') ? WebformSubmissionInterface::STATE_COMPLETED : $webform_submission->getState(); + $enabledStates = (array) ($this->configuration[self::ADDITIONAL][self::STATES] ?? NULL); + if (!in_array($submissionState, $enabledStates)) { + return; + } + $queueStorage = $this->entityTypeManager->getStorage('advancedqueue_queue'); /** @var \Drupal\advancedqueue\Entity\Queue $queue */ $queue = $queueStorage->load('fasit_queue'); diff --git a/modules/os2forms_fbs_handler/os2forms_fbs_handler.install b/modules/os2forms_fbs_handler/os2forms_fbs_handler.install new file mode 100644 index 00000000..4fa0422f --- /dev/null +++ b/modules/os2forms_fbs_handler/os2forms_fbs_handler.install @@ -0,0 +1,39 @@ +listAll('webform.webform.') as $name) { + $config = $configFactory->getEditable($name); + $handlers = $config->get('handlers'); + if (!is_array($handlers)) { + continue; + } + + $changed = FALSE; + + foreach ($handlers as $handlerKey => $handler) { + // $handler['id'] is the handler plugin id. + if (($handler['id'] ?? NULL) !== 'os2forms_fbs') { + continue; + } + $handlers[$handlerKey]['settings']['additional']['states'] = [WebformSubmissionInterface::STATE_COMPLETED]; + $changed = TRUE; + } + + if ($changed) { + $config->set('handlers', $handlers)->save(); + } + } +} diff --git a/modules/os2forms_fbs_handler/src/Plugin/WebformHandler/FbsWebformHandler.php b/modules/os2forms_fbs_handler/src/Plugin/WebformHandler/FbsWebformHandler.php index aa1ae330..33c479c5 100644 --- a/modules/os2forms_fbs_handler/src/Plugin/WebformHandler/FbsWebformHandler.php +++ b/modules/os2forms_fbs_handler/src/Plugin/WebformHandler/FbsWebformHandler.php @@ -42,6 +42,8 @@ final class FbsWebformHandler extends WebformHandlerBase { * The queue id. */ private const QUEUE_ID = 'os2forms_fbs_handler'; + private const string ADDITIONAL = 'additional'; + private const string STATES = 'states'; /** * Constructs an FbsWebformHandler object. @@ -89,6 +91,19 @@ public static function create(ContainerInterface $container, array $configuratio ); } + /** + * {@inheritdoc} + * + * @phpstan-return array + */ + public function defaultConfiguration() { + return [ + self::ADDITIONAL => [ + self::STATES => [WebformSubmissionInterface::STATE_COMPLETED], + ], + ]; + } + /** * {@inheritdoc} * @@ -146,6 +161,31 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta '#default_value' => $this->configuration['password'] ?? '', ]; + // Additional. + // Lifted from EmailWebformHandler::buildConfigurationForm(). + $resultsDisabled = (bool) $this->getWebform()->getSetting('results_disabled'); + $form[self::ADDITIONAL] = [ + '#type' => 'fieldset', + '#title' => $this->t('Additional settings'), + ]; + // Settings: States. + $states = (array) ($this->configuration[self::ADDITIONAL][self::STATES] ?? NULL); + $form[self::ADDITIONAL][self::STATES] = [ + '#type' => 'checkboxes', + '#title' => $this->t('Run handler when …'), + '#options' => [ + WebformSubmissionInterface::STATE_DRAFT_CREATED => $this->t('draft is created.'), + WebformSubmissionInterface::STATE_DRAFT_UPDATED => $this->t('draft is updated.'), + WebformSubmissionInterface::STATE_CONVERTED => $this->t('anonymous submission is converted to authenticated.'), + WebformSubmissionInterface::STATE_COMPLETED => $this->t('submission is completed.'), + WebformSubmissionInterface::STATE_UPDATED => $this->t('submission is updated.'), + WebformSubmissionInterface::STATE_DELETED => $this->t('submission is deleted.'), + WebformSubmissionInterface::STATE_LOCKED => $this->t('submission is locked.'), + ], + '#access' => !$resultsDisabled, + '#default_value' => $resultsDisabled ? [WebformSubmissionInterface::STATE_COMPLETED] : $states, + ]; + return $this->setSettingsParents($form); } @@ -164,12 +204,23 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s ->getValue(['wrapper', 'username']); $this->configuration['password'] = $form_state ->getValue(['wrapper', 'password']); + + $additional = $form_state->getValue(self::ADDITIONAL); + // Clean up states. + $additional[self::STATES] = array_values(array_filter($additional[self::STATES])); + $this->configuration[self::ADDITIONAL] = $additional; } /** * {@inheritdoc} */ public function postSave(WebformSubmissionInterface $webform_submission, $update = TRUE): void { + $submissionState = $webform_submission->getWebform()->getSetting('results_disabled') ? WebformSubmissionInterface::STATE_COMPLETED : $webform_submission->getState(); + $enabledStates = (array) ($this->configuration[self::ADDITIONAL][self::STATES] ?? NULL); + if (!in_array($submissionState, $enabledStates)) { + return; + } + $logger_context = [ 'handler_id' => 'os2forms_fbs', 'channel' => 'webform_submission', From 48d83071a0c404f773477707711459e7ea1d9d4f Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Tue, 23 Jun 2026 14:08:20 +0200 Subject: [PATCH 8/8] Updated CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e57aca61..e5b2a42c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ before starting to add changes. Use example [placed in the end of the page](#exa ## [Unreleased] -- Added the ability to configure on which submission states handlers should run. +- [PR-333](https://github.com/OS2Forms/os2forms/pull/333) + Added the ability to configure on which submission states handlers should run. The default option is to run on the completed state. Changes was made to the following handlers: - Digital post