Skip to content

Commit

Permalink
1015: Added check for digital post
Browse files Browse the repository at this point in the history
  • Loading branch information
rimi-itk committed Sep 23, 2024
1 parent 54e7857 commit f5e66df
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 13 deletions.
4 changes: 4 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,7 @@ USER_SIGNATURE_HEIGHT='2cm'
SF1601_SENDER_LABEL='Aarhus Kommune'
#SF1601_FORSENDELSES_TYPE_IDENTIFIKATOR=''
SF1601_TEST_MODE='true'

# Set to `-1 day`, say, to effectovely disable cache.
# Run `bin/console tvist1:cache:clear` after changing this.
SF1601_POST_FORESPOERG_CACHE_EXPIRE_AT='+1 day'
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ about writing changes to this log.

## [Unreleased]

* [PR-401](https://github.com/itk-dev/naevnssekretariatet/pull/401)
- [PR-402](https://github.com/itk-dev/naevnssekretariatet/pull/402)
Optimized handling of digital post
- [PR-401](https://github.com/itk-dev/naevnssekretariatet/pull/401)
Update itk-dev/serviceplatformen
- [PR-399](https://github.com/itk-dev/naevnssekretariatet/pull/399)
Added `forsendelse-uuid` filtering option to
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"sensio/framework-extra-bundle": "^5.1",
"stof/doctrine-extensions-bundle": "^1.7",
"symfony/asset": "5.4.*",
"symfony/cache": "5.4.*",
"symfony/console": "5.4.*",
"symfony/doctrine-messenger": "5.4.*",
"symfony/dotenv": "5.4.*",
Expand Down
16 changes: 8 additions & 8 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ services:
sender_label: '%env(SF1601_SENDER_LABEL)%'
forsendelses_type_identifikator: '%env(int:SF1601_FORSENDELSES_TYPE_IDENTIFIKATOR)%'
test_mode: '%env(bool:SF1601_TEST_MODE)%'
post_forespoerg_cache_expire_at: '%env(SF1601_POST_FORESPOERG_CACHE_EXPIRE_AT)%'

App\Retry\DigitalPostRetryStrategy:
arguments:
Expand Down
35 changes: 35 additions & 0 deletions src/Command/CacheClearCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Command;

use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

#[AsCommand(
name: 'tvist1:cache:clear',
description: 'Clear Symfony Cache Component cache',
)]
class CacheClearCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);

foreach ([
// Add all caches used in the project here.
new FilesystemAdapter(),
] as $cache) {
if ($cache->clear()) {
$io->success(sprintf('%s cache cleared', $cache::class));
} else {
$io->error(sprintf('Error clearing %s cache', $cache::class));
}
}

return Command::SUCCESS;
}
}
5 changes: 5 additions & 0 deletions src/Command/DigitalPostForespoergCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace App\Command;

use App\Service\SF1601\DigitalPoster;
use ItkDev\Serviceplatformen\Service\SF1601\SF1601;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand Down Expand Up @@ -41,6 +42,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$table->setHeaders(['Identifier', 'Result']);
$identifiers = array_unique($input->getArgument('identifier'));
$type = $input->getOption('type');
if (!in_array($type, SF1601::FORESPOERG_TYPES)) {
throw new \InvalidArgumentException(sprintf('Invalid type: %s. Must be one of %s', $type, implode(', ', SF1601::FORESPOERG_TYPES)));
}

foreach ($identifiers as $identifier) {
$result = $this->digitalPoster->canReceive($type, $identifier);
$table->appendRow([$identifier, is_bool($result) ? json_encode($result) : $result]);
Expand Down
11 changes: 11 additions & 0 deletions src/Controller/HearingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,17 @@ public function hearingPostRequestCreate(CaseEntity $case, DocumentUploader $doc
}

$availableParties = $partyHelper->getRelevantPartiesForHearingPostByCase($case);

foreach ($availableParties as $type => &$parties) {
foreach ($parties as $key => $party) {
if (!$party->canReceiveDigitalPost()) {
$newKey = $key.sprintf(' (%s)', new TranslatableMessage('Cannot receive digital post'));
$parties[$newKey] = $party;
unset($parties[$key]);
}
}
}

$mailTemplates = $mailTemplateHelper->getTemplates('hearing');

$hearingPost = new HearingPostRequest();
Expand Down
17 changes: 17 additions & 0 deletions src/Entity/Party.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ class Party implements LoggableEntityInterface
*/
private $isUnderAddressProtection = false;

/**
* Virtual property set on runtime.
*/
private ?bool $canReceiveDigitalPost = null;

public function __construct()
{
$this->id = Uuid::v4();
Expand Down Expand Up @@ -164,4 +169,16 @@ public function setIsUnderAddressProtection(bool $isUnderAddressProtection): sel

return $this;
}

public function canReceiveDigitalPost(): ?bool
{
return $this->canReceiveDigitalPost;
}

public function setCanReceiveDigitalPost(bool $canReceiveDigitalPost): self
{
$this->canReceiveDigitalPost = $canReceiveDigitalPost;

return $this;
}
}
40 changes: 39 additions & 1 deletion src/Service/PartyHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@
use App\Entity\Party;
use App\Repository\CasePartyRelationRepository;
use App\Repository\PartyRepository;
use App\Service\SF1601\DigitalPoster;
use Doctrine\ORM\EntityManagerInterface;
use ItkDev\Serviceplatformen\Service\SF1601\SF1601;
use Symfony\Component\Form\FormInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

class PartyHelper
{
public function __construct(private EntityManagerInterface $entityManager, private PartyRepository $partyRepository, private CasePartyRelationRepository $relationRepository, private TranslatorInterface $translator)
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly PartyRepository $partyRepository,
private readonly CasePartyRelationRepository $relationRepository,
private readonly TranslatorInterface $translator,
private readonly DigitalPoster $digitalPoster,
)
{
}

Expand Down Expand Up @@ -273,6 +281,9 @@ private function getSortingCounterpartyType(CaseEntity $case)
return reset($counterpartTypes);
}

/**
* @return array<string, Party[]>
*/
public function getRelevantPartiesForHearingPostByCase(CaseEntity $case): array
{
$partyRelations = $this->relationRepository
Expand Down Expand Up @@ -307,9 +318,36 @@ public function getRelevantPartiesForHearingPostByCase(CaseEntity $case): array
// Sort alphabetically
uasort($counterparties, static fn ($a, $b) => $a->getName() <=> $b->getName());

$this->setCanReceiveDigitalPost($parties);
$this->setCanReceiveDigitalPost($counterparties);

return [$this->translator->trans('Parties', [], 'case') => $parties, $this->translator->trans('Counterparties', [], 'case') => $counterparties];
}

/**
* @param Party[] $parties
*/
private function setCanReceiveDigitalPost(array $parties): array
{
foreach ($parties as $party) {
$canReceiveDigitalPost = true;
try {
$identification = $party->getIdentification();
if (IdentificationHelper::IDENTIFIER_TYPE_CPR === $identification->getType()) {
$canReceiveDigitalPost = $this->digitalPoster->canReceive(
SF1601::FORESPOERG_TYPE_DIGITAL_POST,
$identification->getIdentifier()
);
}
$party->setCanReceiveDigitalPost($canReceiveDigitalPost);
} catch (\Throwable $t) {
throw $t;
}
}

return $parties;
}

public function getTransformedRelevantPartiesByCase(CaseEntity $case): array
{
$parties = $this->getRelevantPartiesByCase($case);
Expand Down
25 changes: 22 additions & 3 deletions src/Service/SF1601/DigitalPoster.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
use ItkDev\Serviceplatformen\Service\SF1601\SF1601;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\LoggerInterface;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Uid\Uuid;
use Symfony\Contracts\Cache\ItemInterface;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;

class DigitalPoster
Expand All @@ -27,10 +29,26 @@ public function __construct(private CertificateLocatorHelper $certificateLocator

public function canReceive(string $type, string $identifier): ?bool
{
$service = $this->getSF1601();
$transactionId = Serializer::createUuid();
$cache = new FilesystemAdapter();
$cacheKey = preg_replace(
'#[{}()/\\\\@:]+#',
'_',
implode('|||', [__METHOD__, $type, $identifier])
);

return $cache->get($cacheKey, function (ItemInterface $item) use ($type, $identifier): ?bool {
try {
$service = $this->getSF1601();
$transactionId = Serializer::createUuid();
$result = $service->postForespoerg($transactionId, $type, $identifier);
$item->expiresAt(new \DateTimeImmutable($this->options['post_forespoerg_cache_expire_at']));
} catch (\Throwable $throwable) {
// Never cache is case of error.
$item->expiresAt(new \DateTimeImmutable('2001-01-01'));
}

return $service->postForespoerg($transactionId, $type, $identifier);
return true === ($result['result'] ?? false);
});
}

public function sendDigitalPost(DigitalPost $digitalPost, DigitalPost\Recipient $recipient)
Expand Down Expand Up @@ -174,6 +192,7 @@ private function resolveOptions(array $options): array
->setAllowedTypes('sender_label', 'string')
;
})
->setDefault('post_forespoerg_cache_expire_at', '+1 day')
->resolve($options)
;
}
Expand Down

0 comments on commit f5e66df

Please sign in to comment.