Skip to content

Commit fdb5ee6

Browse files
committed
5189: Improved digital post test command
1 parent 3191624 commit fdb5ee6

File tree

1 file changed

+137
-12
lines changed

1 file changed

+137
-12
lines changed

modules/os2forms_digital_post/src/Drush/Commands/DigitalPostTestCommands.php

Lines changed: 137 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace Drupal\os2forms_digital_post\Drush\Commands;
44

5+
use DigitalPost\MeMo\Action;
6+
use DigitalPost\MeMo\EntryPoint;
7+
use DigitalPost\MeMo\Reservation;
58
use Drupal\Component\Serialization\Yaml;
69
use Drupal\Core\DependencyInjection\AutowireTrait;
710
use Drupal\Core\Utility\Token;
@@ -10,10 +13,16 @@
1013
use Drupal\os2forms_digital_post\Helper\Settings;
1114
use Drupal\os2forms_digital_post\Model\Document;
1215
use Drush\Commands\DrushCommands;
16+
use ItkDev\Serviceplatformen\Service\SF1601\Serializer;
1317
use ItkDev\Serviceplatformen\Service\SF1601\SF1601;
1418
use Symfony\Component\Console\Exception\InvalidArgumentException;
19+
use Symfony\Component\Console\Exception\InvalidOptionException;
1520
use Symfony\Component\Console\Style\SymfonyStyle;
1621
use Symfony\Component\DependencyInjection\Attribute\Autowire;
22+
use Symfony\Component\OptionsResolver\Exception\ExceptionInterface;
23+
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
24+
use Symfony\Component\OptionsResolver\Options;
25+
use Symfony\Component\OptionsResolver\OptionsResolver;
1726
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
1827

1928
/**
@@ -44,14 +53,20 @@ public function __construct(
4453
* @param array $options
4554
* The options.
4655
*
47-
* @option string subject
48-
* The subject. Can contain HTML.
49-
* @option string message
50-
* The message to send. Can contain HTML.
51-
* @option string digital-post-type
52-
* The digital post type to use.
53-
* @option bool dump-digital-post-settings
54-
* Dump digital post settings.
56+
* @option subject
57+
* The subject. Can contain HTML.
58+
* @option message
59+
* The message to send. Can contain HTML.
60+
* @option digital-post-type
61+
* The digital post type to use.
62+
* @option dump-digital-post-settings
63+
* Dump digital post settings.
64+
* @option memo-version
65+
* MeMo version (1.1 or 1.2). If not set, a proper default will be used.
66+
* @option action
67+
* MeMo actions, e.g. 'action=INFORMATION&label=Vigtig%20information&entrypoint=https://example.com'
68+
* @option filename
69+
* The main document filename (used to test invalid filenames (cf. https://digitaliser.dk/digital-post/nyhedsarkiv/2024/nov/oeget-validering-i-digital-post))
5570
*
5671
* @phpstan-param array<string> $recipients
5772
* @phpstan-param array<string, mixed> $options
@@ -66,6 +81,9 @@ public function send(
6681
'message' => 'This is a test message from os2forms_digital_post sent on [current-date:html_datetime].',
6782
'digital-post-type' => SF1601::TYPE_AUTOMATISK_VALG,
6883
'dump-digital-post-settings' => FALSE,
84+
'memo-version' => NULL,
85+
'action' => [],
86+
'filename' => 'os2forms_digital_post',
6987
],
7088
): void {
7189
$io = new SymfonyStyle($this->input(), $this->output());
@@ -89,7 +107,7 @@ public function send(
89107
$document = new Document(
90108
$content,
91109
Document::MIME_TYPE_PDF,
92-
'os2forms_digital_post.pdf'
110+
$options['filename'] . '.pdf',
93111
);
94112

95113
$type = $options['digital-post-type'];
@@ -98,21 +116,41 @@ public function send(
98116
throw new InvalidArgumentException(sprintf('Invalid type: %s. Must be one of %s.', $quote($type), implode(', ', array_map($quote, SF1601::TYPES))));
99117
}
100118

119+
$meMoVersion = $options['memo-version'];
120+
if ($meMoVersion) {
121+
$meMoVersion = (float) $meMoVersion;
122+
$allowedValues = [SF1601::MEMO_1_1, SF1601::MEMO_1_2];
123+
if (!in_array($meMoVersion, $allowedValues, TRUE)) {
124+
$quote = static fn($value) => var_export($value, TRUE);
125+
throw new InvalidArgumentException(sprintf(
126+
'Invalid MeMo version: %s. Must be one of %s.',
127+
$quote($meMoVersion),
128+
implode(', ', array_map($quote, $allowedValues))
129+
));
130+
}
131+
}
132+
101133
$io->section('Digital post');
102134
$io->definitionList(
103135
['Type' => $type],
136+
['Document' => sprintf('%s (%s) (sanitized: %s)', $document->filename, $document->mimeType, SF1601::sanitizeFilename($document->filename))],
104137
['Subject' => $subject],
105-
['Message' => $message]
138+
['Message' => $message],
139+
['MeMe version' => $meMoVersion],
106140
);
107141

142+
$actions = array_map($this->buildAction(...), $options['action']);
143+
108144
foreach ($recipients as $recipient) {
109145
try {
110146
$io->writeln(sprintf('Recipient: %s', $recipient));
111147
$recipientLookupResult = $this->digitalPostHelper->lookupRecipient($recipient);
112-
$actions = [];
113148

114149
$meMoMessage = $this->digitalPostHelper->getMeMoHelper()->buildMessage($recipientLookupResult, $senderLabel,
115150
$messageLabel, $document, $actions);
151+
if ($meMoVersion) {
152+
$meMoMessage->setMemoVersion($meMoVersion);
153+
}
116154
$forsendelse = $this->digitalPostHelper->getForsendelseHelper()->buildForsendelse($recipientLookupResult,
117155
$messageLabel, $document);
118156

@@ -122,7 +160,7 @@ public function send(
122160
$forsendelse
123161
);
124162

125-
$io->success(sprintf('Digital post sent to %s', $recipient));
163+
$io->success(sprintf('Digital post sent to %s (MeMo %s)', $recipient, $meMoMessage->getMemoVersion()));
126164
}
127165
catch (\Throwable $throwable) {
128166
$io->error(sprintf('Error sending digital post to %s:', $recipient));
@@ -158,4 +196,91 @@ private function dumpDigitalPostSettings(SymfonyStyle $io): void {
158196
]);
159197
}
160198

199+
/**
200+
* Build MeMo action.
201+
*
202+
* Lifted from KombiPostAfsendCommand::buildAction().
203+
*
204+
* @see KombiPostAfsendCommand::buildAction()
205+
*/
206+
private function buildAction(string $spec): Action {
207+
parse_str($spec, $options);
208+
$resolver = $this->getActionOptionsResolver();
209+
try {
210+
$options = $resolver->resolve($options);
211+
}
212+
catch (ExceptionInterface $exception) {
213+
throw new InvalidOptionException(sprintf(
214+
'Invalid action %s: %s',
215+
json_encode($spec),
216+
$exception->getMessage()
217+
));
218+
}
219+
220+
$action = (new Action())
221+
->setActionCode($options['action'])
222+
->setLabel($options['label']);
223+
if (SF1601::ACTION_AFTALE === $options['action']) {
224+
$reservation = (new Reservation())
225+
->setStartDateTime(new \DateTime('+2 days'))
226+
->setEndDateTime(new \DateTime('+2 days 1 hour'))
227+
->setLocation('Meeting room 1')
228+
->setAbstract('Abstract')
229+
->setDescription('Description')
230+
->setOrganizerName('Organizer')
231+
->setOrganizerMail('[email protected]')
232+
->setReservationUUID(Serializer::createUuid());
233+
$action->setReservation($reservation);
234+
}
235+
elseif ($options['entrypoint']) {
236+
$action->setEntryPoint(
237+
(new EntryPoint())
238+
->setUrl($options['entrypoint'])
239+
);
240+
}
241+
242+
if ($options['endDateTime']) {
243+
$action->setEndDateTime(new \DateTime($options['endDateTime']));
244+
}
245+
246+
return $action;
247+
}
248+
249+
/**
250+
* Get actions options resolver.
251+
*
252+
* @see KombiPostAfsendCommand::getActionOptionsResolver()
253+
*/
254+
private function getActionOptionsResolver(): OptionsResolver {
255+
$resolver = new OptionsResolver();
256+
$resolver
257+
->setRequired([
258+
'action',
259+
'label',
260+
])
261+
->setDefaults([
262+
'endDateTime' => NULL,
263+
'entrypoint' => NULL,
264+
])
265+
->setInfo('action', sprintf('The action name (one of %s)', implode(', ', SF1601::ACTIONS)))
266+
->setInfo('label', 'The action label')
267+
->setInfo('endDateTime', 'The end time e.g. "2022-12-02" or "14 days"')
268+
->setInfo('entrypoint', 'The entry point (an URL)')
269+
->setAllowedValues('action', static function ($value) {
270+
return in_array($value, SF1601::ACTIONS, TRUE);
271+
})
272+
->setNormalizer('entrypoint', static function (Options $options, $value) {
273+
if (NULL === $value && SF1601::ACTION_AFTALE !== $options['action']) {
274+
throw new InvalidOptionsException(sprintf(
275+
'Action entrypoint is required for all actions but %s',
276+
SF1601::ACTION_AFTALE
277+
));
278+
}
279+
280+
return $value;
281+
});
282+
283+
return $resolver;
284+
}
285+
161286
}

0 commit comments

Comments
 (0)