Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ before starting to add changes. Use example [placed in the end of the page](#exa

## [Unreleased]

- [PR-325](https://github.com/OS2Forms/os2forms/pull/325)
Added NemID first name, middle name and last name webform elements.
- Moved digital signature configuration (which attachment to sign and the
signature validation text position) from the *OS2Forms Attachment* element
onto the *Digital Signature* webform handler. Includes an automatic
migration update hook for existing webforms.

## [5.1.0] 2026-06-03

Expand Down
11 changes: 11 additions & 0 deletions build_release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ git merge --no-ff origin/feature/add-first-middle-and-last-name-nemid-elements
git checkout --theirs CHANGELOG.md
git add CHANGELOG.md
git commit -m "Merge remote-tracking branch 'origin/feature/add-first-middle-and-last-name-nemid-elements' into selvbetjening.aarhuskommune.dk"
git merge --no-ff origin/feature/add-states-configuration-to-handlers
git checkout --theirs CHANGELOG.md
git add CHANGELOG.md
git commit -m "Merge remote-tracking branch 'origin/feature/add-states-configuration-to-handlers' into selvbetjening.aarhuskommune.dk"
git merge --no-ff origin/feature/move-digital-signature-configuration-to-handler
# Manually handle conflicts in modules/os2forms_digital_signature/os2forms_digital_signature.install
# git add modules/os2forms_digital_signature/os2forms_digital_signature.install
git checkout --theirs CHANGELOG.md
git add CHANGELOG.md
git commit -m "Merge remote-tracking branch 'origin/feature/move-digital-signature-configuration-to-handler' into selvbetjening.aarhuskommune.dk"


docker run --rm --volume .:/app itkdev/php8.4-fpm:latest sed --in-place '1i This is a hack so the CHANGELOG is messed up. \nGenerated by build_release.sh' CHANGELOG.md
git add CHANGELOG.md
Expand Down
17 changes: 17 additions & 0 deletions modules/os2forms_attachment/src/Element/AttachmentElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ public static function getFileContent(array $element, WebformSubmissionInterface
if ($element['#export_type'] === 'pdf') {
$file_path = NULL;

// Digital signature settings live on the digital signature handler.
// Resolving them here ensures all consumers of the element (email
// handlers, attachment downloads) serve an already signed document
// and render the validation text consistently.
$elementKey = $element['#webform_key'] ?? NULL;
if ($elementKey !== NULL) {
foreach ($webform_submission->getWebform()->getHandlers('os2forms_digital_signature') as $handler) {
$settings = $handler->getConfiguration()['settings'] ?? [];
if ($handler->isEnabled() && ($settings['attachment_element'] ?? '') === $elementKey) {
$element['#digital_signature'] = TRUE;
$element['#digital_signature_position'] = $settings['signature_position']
?? Os2formsAttachmentPrintBuilder::SIGNATURE_POSITION_AFTER_CONTENT;
break;
}
}
}

// If attachment with digital signatur, check if we already have one.
if (isset($element['#digital_signature']) && $element['#digital_signature']) {
// Get scheme.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\Twig\WebformTwigExtension;
use Drupal\webform\Utility\WebformElementHelper;
use Drupal\os2forms_attachment\Os2formsAttachmentPrintBuilder;
use Drupal\webform_attachment\Plugin\WebformElement\WebformAttachmentBase;

/**
Expand All @@ -28,8 +27,6 @@ protected function defineDefaultProperties() {
'view_mode' => 'html',
'template' => '',
'export_type' => '',
'digital_signature' => '',
'digital_signature_position' => Os2formsAttachmentPrintBuilder::SIGNATURE_POSITION_AFTER_CONTENT,
'exclude_empty' => '',
'exclude_empty_checkbox' => '',
'excluded_elements' => '',
Expand Down Expand Up @@ -91,28 +88,6 @@ public function form(array $form, FormStateInterface $form_state) {
'html' => $this->t('HTML'),
],
];
$form['attachment']['digital_signature'] = [
'#type' => 'checkbox',
'#title' => $this->t('Digital signature'),
];
$form['attachment']['digital_signature_position'] = [
'#type' => 'select',
'#title' => $this->t('Digital signature position'),
'#description' => $this->t('Select where the digital signature validation text should be placed in the PDF document.'),
'#options' => [
Os2formsAttachmentPrintBuilder::SIGNATURE_POSITION_FOOTER => $this->t('Footer (repeats on every page)'),
Os2formsAttachmentPrintBuilder::SIGNATURE_POSITION_HEADER => $this->t('Header (repeats on every page)'),
Os2formsAttachmentPrintBuilder::SIGNATURE_POSITION_AFTER_CONTENT => $this->t('After content (end of document)'),
Os2formsAttachmentPrintBuilder::SIGNATURE_POSITION_BEFORE_CONTENT => $this->t('Before content (start of document)'),
],
'#default_value' => Os2formsAttachmentPrintBuilder::SIGNATURE_POSITION_AFTER_CONTENT,
'#states' => [
'visible' => [
':input[name="properties[digital_signature]"]' => ['checked' => TRUE],
],
],
];

// Set #access so that help is always visible.
WebformElementHelper::setPropertyRecursive($form['attachment']['help'], '#access', TRUE);

Expand Down
32 changes: 32 additions & 0 deletions modules/os2forms_digital_post/os2forms_digital_post.install
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

use Drupal\os2forms_digital_post\Helper\BeskedfordelerHelper;
use Drupal\webform\WebformSubmissionInterface;

/**
* Implements hook_schema().
Expand All @@ -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();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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],
],
];
}

Expand Down Expand Up @@ -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('<b>draft is created</b>.'),
WebformSubmissionInterface::STATE_DRAFT_UPDATED => $this->t('<b>draft is updated</b>.'),
WebformSubmissionInterface::STATE_CONVERTED => $this->t('anonymous <b>submission is converted</b> to authenticated.'),
WebformSubmissionInterface::STATE_COMPLETED => $this->t('<b>submission is completed</b>.'),
WebformSubmissionInterface::STATE_UPDATED => $this->t('<b>submission is updated</b>.'),
WebformSubmissionInterface::STATE_DELETED => $this->t('<b>submission is deleted</b>.'),
WebformSubmissionInterface::STATE_LOCKED => $this->t('<b>submission is locked</b>.'),
],
'#access' => !$resultsDisabled,
'#default_value' => $resultsDisabled ? [WebformSubmissionInterface::STATE_COMPLETED] : $states,
];

return $this->setSettingsParents($form);
}

Expand Down Expand Up @@ -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;
}

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

Expand Down
14 changes: 11 additions & 3 deletions modules/os2forms_digital_signature/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@ The signature server consists of two parts. A frontend module

### Activating Digital Signature

1. Add the OS2forms attachment element to the form.
2. Indicate that the OS2Forms attachment requires a digital signature.
3. Add the Digital Signature Handler to the webform.
1. Add an attachment-style element to the form (either *OS2Forms Attachment* — generated PDF — or
*OS2forms digital signature document* — uploaded PDF).
2. Add the **Digital Signature** handler to the webform.
3. In the handler configuration, pick the attachment element to sign from the **Attachment element to sign**
dropdown, and choose where the signature validation text should be placed in the generated PDF
(the position only applies to *OS2Forms Attachment* elements; it is ignored for uploaded PDFs).
4. If the form requires an email handler, ensure the trigger is set to **...when submission is locked** in the handler’s
*Additional settings*.

> [!NOTE]
> Prior to this release, the attachment element exposed `Digital signature` and `Digital signature position` properties
> directly. These settings have moved to the handler. Existing forms are migrated automatically by
> `os2forms_digital_signature_update_10001()`.

### Flow Explained

1. Upon form submission, a PDF is generated, saved in the private directory, and sent to the signature service via URL.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ package: 'OS2Forms'
core_version_requirement: ^9 || ^10
dependencies:
- 'webform:webform'
- 'os2forms:os2forms_attachment'

configure: os2forms_digital_signature.settings
Loading
Loading