From 3a961483d0c0af5bab44c65eb00e1c04d803f495 Mon Sep 17 00:00:00 2001 From: Mikkel Ricky Date: Fri, 3 May 2024 12:44:27 +0200 Subject: [PATCH] Added support for Key --- .github/PULL_REQUEST_TEMPLATE.md | 25 +++ .github/workflows/pr.yaml | 42 ++--- .markdownlint.jsonc | 13 ++ CHANGELOG.md | 3 + README.md | 37 +++-- composer.json | 63 ++++---- drush.services.yml | 6 + os2forms_get_organized.services.yml | 3 +- phpstan.neon | 11 ++ scripts/code-analysis | 48 ++++++ .../Commands/GetOrganizedTestCommands.php | 38 +++++ src/Form/SettingsForm.php | 153 +++++++++--------- src/Helper/ArchiveHelper.php | 52 ++++-- src/Helper/Settings.php | 130 +++++++-------- .../AdvancedQueue/JobType/ArchiveDocument.php | 2 +- 15 files changed, 388 insertions(+), 238 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .markdownlint.jsonc create mode 100644 drush.services.yml create mode 100644 phpstan.neon create mode 100755 scripts/code-analysis create mode 100644 src/Drush/Commands/GetOrganizedTestCommands.php diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..dc5b4ae --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,25 @@ +#### Link to ticket + +Please add a link to the ticket being addressed by this change. + +#### Description + +Please include a short description of the suggested change and the reasoning behind the approach you have chosen. + +#### Screenshot of the result + +If your change affects the user interface you should include a screenshot of the result with the pull request. + +#### Checklist + +- [ ] My code is covered by test cases. +- [ ] My code passes our test (all our tests). +- [ ] My code passes our static analysis suite. +- [ ] My code passes our continuous integration process. + +If your code does not pass all the requirements on the checklist you have to add a comment explaining why this change +should be exempt from the list. + +#### Additional comments or questions + +If you have any further comments or questions for the reviewer please add them here. diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index f42c312..a181a0d 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -49,6 +49,9 @@ jobs: composer validate --strict composer.json # Check that dependencies resolve. composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction + - name: Check that composer file is normalized + run: | + composer normalize --dry-run php-check-coding-standards: name: PHP - Check Coding Standards @@ -109,34 +112,17 @@ jobs: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- - - name: drupal-check + - name: Code analysis run: | - # We need a Drupal project to run drupal-check (cf. https://github.com/mglaman/drupal-check#usage) - # Install Drupal - composer --no-interaction create-project drupal/recommended-project:^9 --stability=dev drupal - # Copy our module source code into the Drupal module folder. - mkdir -p drupal/web/modules/contrib/os2forms_get_organized - cp -r os2forms_get_organized.* composer.json src drupal/web/modules/contrib/os2forms_get_organized - # Add our module as a composer repository. - composer --no-interaction --working-dir=drupal config repositories.os2forms/os2forms_get_organized path web/modules/contrib/os2forms_get_organized - # Restore Drupal composer repository. - composer --no-interaction --working-dir=drupal config repositories.drupal composer https://packages.drupal.org/8 - - composer --no-interaction --working-dir=drupal config --no-plugins allow-plugins.cweagans/composer-patches true - composer --no-interaction --working-dir=drupal config --no-plugins allow-plugins.zaporylie/composer-drupal-optimizations true - composer --no-interaction --working-dir=drupal config --no-plugins allow-plugins.simplesamlphp/composer-module-installer true - # @see https://getcomposer.org/doc/03-cli.md#modifying-extra-values - composer --no-interaction --working-dir=drupal config --no-plugins --json extra.enable-patching true + ./scripts/code-analysis - # Require our module. - composer --no-interaction --working-dir=drupal require 'os2forms/os2forms_get_organized:*' + coding-standards-markdown: + name: Markdown coding standards + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@master - # Check code - composer --no-interaction --working-dir=drupal require --dev drupal/core-dev - cd drupal/web/modules/contrib/os2forms_get_organized - # Remove our non-dev dependencies to prevent duplicated Drupal installation - # PHP Fatal error: Cannot redeclare drupal_get_filename() (previously declared in /home/runner/work/os2forms_get_organized/os2forms_get_organized/drupal/web/modules/contrib/os2forms_get_organized/vendor/drupal/core/includes/bootstrap.inc:190) in /home/runner/work/os2forms_get_organized/os2forms_get_organized/drupal/web/core/includes/bootstrap.inc on line 190 - # Use sed to remove the "require" property in composer.json - sed -i '/^\s*"require":/,/^\s*}/d' composer.json - composer --no-interaction install - composer code-analysis + - name: Coding standards + run: | + docker run --rm --volume $PWD:/md peterdavehello/markdownlint markdownlint --ignore vendor --ignore LICENSE.md '**/*.md' diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc new file mode 100644 index 0000000..a28c580 --- /dev/null +++ b/.markdownlint.jsonc @@ -0,0 +1,13 @@ +{ + "default": true, + // https://github.com/DavidAnson/markdownlint/blob/main/doc/md013.md + "line-length": { + "line_length": 120, + "code_blocks": false, + "tables": false + }, + // https://github.com/DavidAnson/markdownlint/blob/main/doc/md024.md + "no-duplicate-heading": { + "siblings_only": true + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md index f38d31d..cb1a4c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ about writing changes to this log. ## [Unreleased] +* [PR-1](https://github.com/itk-dev/os2forms_get_organized/pull/1) + Added support for os2web_key + ## [1.1.5] 04.01.2024 * Disallowed `webform_entity_print_attachment:pdf` attachment element. diff --git a/README.md b/README.md index e07615b..558d6ed 100644 --- a/README.md +++ b/README.md @@ -11,24 +11,37 @@ vendor/bin/drush pm:enable os2forms_get_organized ## Settings -Set GetOrganized `username`, `password` and `base url` -on `/admin/os2forms_get_organized/settings`. - -You can also test that the provided -details work on `/admin/os2forms_get_organized/settings`. +Go to `/admin/os2forms_get_organized/settings` and configure the module. ## Coding standards -Check coding standards: +Our coding are checked by GitHub Actions (cf. [.github/workflows/pr.yml](.github/workflows/pr.yml)). Use the commands +below to run the checks locally. -```sh -docker run --rm --interactive --tty --volume ${PWD}:/app itkdev/php8.1-fpm:latest composer install -docker run --rm --interactive --tty --volume ${PWD}:/app itkdev/php8.1-fpm:latest composer coding-standards-check +### PHP + +```shell +docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.1-fpm composer install +# Fix (some) coding standards issues +docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.1-fpm composer coding-standards-apply +# Check that code adheres to the coding standards +docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.1-fpm composer coding-standards-check +``` + +### Markdown + +```shell +docker run --rm --volume $PWD:/md peterdavehello/markdownlint markdownlint --ignore vendor --ignore LICENSE.md '**/*.md' --fix +docker run --rm --volume $PWD:/md peterdavehello/markdownlint markdownlint --ignore vendor --ignore LICENSE.md '**/*.md' ``` -Apply coding standards: +## Code analysis + +We use [PHPStan](https://phpstan.org/) for static code analysis. + +Running statis code analysis on a standalone Drupal module is a bit tricky, so we use a helper script to run the +analysis: ```shell -docker run --rm --interactive --tty --volume ${PWD}:/app itkdev/php8.1-fpm:latest composer coding-standards-apply -docker run --rm --interactive --tty --volume ${PWD}:/app node:18 yarn --cwd /app coding-standards-apply +docker run --rm --volume ${PWD}:/app --workdir /app itkdev/php8.1-fpm ./scripts/code-analysis ``` diff --git a/composer.json b/composer.json index eaf1a5a..fcbb6a7 100644 --- a/composer.json +++ b/composer.json @@ -1,61 +1,64 @@ { "name": "os2forms/os2forms_get_organized", "description": "OS2Forms GetOrganized integration", - "type": "drupal-module", "license": "MIT", + "type": "drupal-module", "authors": [ { "name": "Jeppe Kuhlmann Andersen", "email": "jekua@aarhus.dk" } ], - "minimum-stability": "dev", - "prefer-stable": true, - "repositories": [ - { - "type": "composer", - "url": "https://packages.drupal.org/8" - } - ], "require": { - "itk-dev/getorganized-api-client-php": "^1.2", - "drupal/webform": "^6.1", "drupal/advancedqueue": "^1.0", - "symfony/options-resolver": "^5.4", - "os2forms/os2forms": "^3.13" + "drupal/key": "^1.17", + "drupal/webform": "^6.1", + "itk-dev/getorganized-api-client-php": "^1.2", + "os2forms/os2forms": "^3.13", + "symfony/options-resolver": "^5.4" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "drupal/coder": "^8.3", + "ergebnis/composer-normalize": "^2.42", "mglaman/drupal-check": "^1.4" }, + "repositories": [ + { + "type": "composer", + "url": "https://packages.drupal.org/8" + } + ], + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "allow-plugins": { + "cweagans/composer-patches": true, + "dealerdirect/phpcodesniffer-composer-installer": true, + "ergebnis/composer-normalize": true, + "simplesamlphp/composer-module-installer": true, + "zaporylie/composer-drupal-optimizations": true + } + }, "scripts": { + "code-analysis": [ + "@code-analysis/drupal-check" + ], "code-analysis/drupal-check": [ "# @see https://github.com/mglaman/drupal-check/issues/261#issuecomment-1030141772 for details on exclude-dir value", "drupal-check --deprecations --analysis --exclude-dir='vendor,*/Client/*' *.* src" ], - "code-analysis": [ - "@code-analysis/drupal-check" + "coding-standards-apply": [ + "@coding-standards-apply/phpcs" ], - "coding-standards-check/phpcs": [ - "vendor/bin/phpcs --standard=phpcs.xml.dist" + "coding-standards-apply/phpcs": [ + "vendor/bin/phpcbf --standard=phpcs.xml.dist" ], "coding-standards-check": [ "@coding-standards-check/phpcs" ], - "coding-standards-apply/phpcs": [ - "vendor/bin/phpcbf --standard=phpcs.xml.dist" - ], - "coding-standards-apply": [ - "@coding-standards-apply/phpcs" + "coding-standards-check/phpcs": [ + "vendor/bin/phpcs --standard=phpcs.xml.dist" ] - }, - "config": { - "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true, - "zaporylie/composer-drupal-optimizations": true, - "cweagans/composer-patches": true, - "simplesamlphp/composer-module-installer": true - } } } diff --git a/drush.services.yml b/drush.services.yml new file mode 100644 index 0000000..3fd4106 --- /dev/null +++ b/drush.services.yml @@ -0,0 +1,6 @@ +services: + Drupal\os2forms_get_organized\Drush\Commands\GetOrganizedTestCommands: + arguments: + - '@Drupal\os2forms_get_organized\Helper\ArchiveHelper' + tags: + - { name: drush.command } diff --git a/os2forms_get_organized.services.yml b/os2forms_get_organized.services.yml index 6635ece..94f1a6c 100644 --- a/os2forms_get_organized.services.yml +++ b/os2forms_get_organized.services.yml @@ -1,7 +1,8 @@ services: Drupal\os2forms_get_organized\Helper\Settings: arguments: - - "@keyvalue" + - "@config.factory" + - "@key.repository" Drupal\os2forms_get_organized\Helper\ArchiveHelper: arguments: diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..8b1d88e --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,11 @@ +parameters: + level: 6 + paths: + - src + + ignoreErrors: + - '#Unsafe usage of new static\(\).#' + +# Local Variables: +# mode: yaml +# End: diff --git a/scripts/code-analysis b/scripts/code-analysis new file mode 100755 index 0000000..2ef69d0 --- /dev/null +++ b/scripts/code-analysis @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +script_dir=$(pwd) +module_name=$(basename "$script_dir") +drupal_dir=vendor/drupal-module-code-analysis +# Relative to $drupal_dir +module_path=web/modules/contrib/$module_name + +cd "$script_dir" || exit + +drupal_composer() { + composer --working-dir="$drupal_dir" --no-interaction "$@" +} + +# Create new Drupal 9 project +if [ ! -f "$drupal_dir/composer.json" ]; then + composer --no-interaction create-project drupal/recommended-project:^9 "$drupal_dir" +fi +# Copy our code into the modules folder + +# Clean up +rm -fr "${drupal_dir:?}/$module_path" + +# https://stackoverflow.com/a/15373763 +# rsync --archive --compress . --filter=':- .gitignore' --exclude "$drupal_dir" --exclude .git "$drupal_dir/$module_path" + +# The rsync command in not available in itkdev/php8.1-fpm + +git config --global --add safe.directory /app +# Copy all module files not ignored by git into module path +# (cf. https://stackoverflow.com/a/77197460) +for f in $(git ls-files --cached --others --exclude-standard); do + mkdir -p "$drupal_dir/$module_path/$(dirname "$f")" + cp "$f" "$drupal_dir/$module_path/$f" +done + +drupal_composer config minimum-stability dev + +# Allow ALL plugins +# https://getcomposer.org/doc/06-config.md#allow-plugins +drupal_composer config --no-plugins allow-plugins true + +drupal_composer require wikimedia/composer-merge-plugin +drupal_composer config extra.merge-plugin.include "$module_path/composer.json" +# https://www.drupal.org/project/drupal/issues/3220043#comment-14845434 +drupal_composer require --dev symfony/phpunit-bridge + +# Run PHPStan +(cd "$drupal_dir/$module_path" && ../../../../vendor/bin/phpstan) diff --git a/src/Drush/Commands/GetOrganizedTestCommands.php b/src/Drush/Commands/GetOrganizedTestCommands.php new file mode 100644 index 0000000..36ad0ff --- /dev/null +++ b/src/Drush/Commands/GetOrganizedTestCommands.php @@ -0,0 +1,38 @@ +helper->pingApi(); + $this->io()->success('Successfully connected to Get Organized API'); + } + catch (\Throwable $t) { + $this->io()->error($t->getMessage()); + } + + } + +} diff --git a/src/Form/SettingsForm.php b/src/Form/SettingsForm.php index ad6ab88..21579a1 100644 --- a/src/Form/SettingsForm.php +++ b/src/Form/SettingsForm.php @@ -2,47 +2,60 @@ namespace Drupal\os2forms_get_organized\Form; -use Drupal\Core\Form\FormBase; +use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Form\ConfigFormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; -use Drupal\os2forms_get_organized\Helper\Settings; +use Drupal\os2forms_get_organized\Helper\ArchiveHelper; use ItkDev\GetOrganized\Client; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\OptionsResolver\Exception\ExceptionInterface as OptionsResolverException; /** * GetOrganized settings form. */ -class SettingsForm extends FormBase { +class SettingsForm extends ConfigFormBase { use StringTranslationTrait; - public const GET_ORGANIZED_USERNAME = 'get_organized_username'; - public const GET_ORGANIZED_PASSWORD = 'get_organized_password'; + public const CONFIG_NAME = 'os2forms_get_organized.settings'; + public const GET_ORGANIZED_BASE_URL = 'get_organized_base_url'; + public const KEY = 'key'; - /** - * The settings. - * - * @var \Drupal\os2forms_get_organized\Helper\Settings - */ - private Settings $settings; + public const ACTION_PING_API = 'action_ping_api'; /** - * Constructor. + * {@inheritdoc} */ - public function __construct(Settings $settings) { - $this->settings = $settings; + public function __construct( + ConfigFactoryInterface $config_factory, + private readonly ArchiveHelper $helper, + ) { + parent::__construct($config_factory); } /** * {@inheritdoc} + * + * @phpstan-return self */ - public static function create(ContainerInterface $container): SettingsForm { + public static function create(ContainerInterface $container): self { return new static( - $container->get(Settings::class), + $container->get('config.factory'), + $container->get(ArchiveHelper::class) ); } + /** + * {@inheritdoc} + * + * @phpstan-return array + */ + protected function getEditableConfigNames() { + return [ + self::CONFIG_NAME, + ]; + } + /** * {@inheritdoc} */ @@ -57,40 +70,38 @@ public function getFormId() { * @phpstan-return array */ public function buildForm(array $form, FormStateInterface $form_state): array { - - $form[self::GET_ORGANIZED_USERNAME] = [ - '#type' => 'textfield', - '#title' => $this->t('Username'), - '#required' => TRUE, - '#default_value' => $this->settings->getUsername(), - ]; - - $form[self::GET_ORGANIZED_PASSWORD] = [ - '#type' => 'textfield', - '#title' => $this->t('Password'), - '#required' => TRUE, - '#default_value' => $this->settings->getPassword(), + $form = parent::buildForm($form, $form_state); + $config = $this->config(self::CONFIG_NAME); + + $form[self::KEY] = [ + '#type' => 'key_select', + '#key_filters' => [ + 'type' => 'user_password', + ], + '#title' => $this->t('Key'), + '#default_value' => $config->get(self::KEY), ]; $form[self::GET_ORGANIZED_BASE_URL] = [ '#type' => 'textfield', '#title' => $this->t('GetOrganized base url'), '#required' => TRUE, - '#default_value' => $this->settings->getBaseUrl(), + '#default_value' => $config->get(self::GET_ORGANIZED_BASE_URL), '#description' => $this->t('GetOrganized base url. Example: "https://ad.go.aarhuskommune.dk/_goapi"'), ]; - $form['actions']['#type'] = 'actions'; + $form['actions']['ping_api'] = [ + '#type' => 'container', - $form['actions']['submit'] = [ - '#type' => 'submit', - '#value' => $this->t('Save settings'), - ]; + self::ACTION_PING_API => [ + '#type' => 'submit', + '#name' => self::ACTION_PING_API, + '#value' => $this->t('Ping API'), + ], - $form['actions']['testSettings'] = [ - '#type' => 'submit', - '#name' => 'testSettings', - '#value' => $this->t('Test provided information'), + 'message' => [ + '#markup' => $this->t('Note: Pinging the API will used saved config.'), + ], ]; return $form; @@ -101,55 +112,41 @@ public function buildForm(array $form, FormStateInterface $form_state): array { * * @phpstan-param array $form */ - public function submitForm(array &$form, FormStateInterface $formState): void { - $username = $formState->getValue(self::GET_ORGANIZED_USERNAME); - $password = $formState->getValue(self::GET_ORGANIZED_PASSWORD); - $baseUrl = $formState->getValue(self::GET_ORGANIZED_BASE_URL); - - $triggeringElement = $formState->getTriggeringElement(); - if ('testSettings' === ($triggeringElement['#name'] ?? NULL)) { - $this->testSettings($username, $password, $baseUrl); + public function validateForm(array &$form, FormStateInterface $form_state): void { + if (self::ACTION_PING_API === ($form_state->getTriggeringElement()['#name'] ?? NULL)) { return; } - try { - $settings[self::GET_ORGANIZED_USERNAME] = $username; - $settings[self::GET_ORGANIZED_PASSWORD] = $password; - $settings[self::GET_ORGANIZED_BASE_URL] = $baseUrl; - - $this->settings->setSettings($settings); - $this->messenger()->addStatus($this->t('Settings saved')); - } - catch (OptionsResolverException $exception) { - $this->messenger()->addError($this->t('Settings not saved (@message)', ['@message' => $exception->getMessage()])); - } - - $this->messenger()->addStatus($this->t('Settings saved')); + parent::validateForm($form, $form_state); } /** - * Test settings by making some arbitrary call to the GetOrganized API. + * {@inheritdoc} + * + * @phpstan-param array $form */ - private function testSettings(string $username, string $password, string $baseUrl): void { - try { - $client = new Client($username, $password, $baseUrl); - /** @var \ItkDev\GetOrganized\Service\Tiles $tileService */ - $tileService = $client->api('tiles'); - - $result = $tileService->GetTilesNavigation(); - - if (empty($result)) { - $message = $this->t('Error occurred while testing the GetOrganized API with provided settings.'); - $this->messenger()->addError($message); + public function submitForm(array &$form, FormStateInterface $form_state): void { + if (self::ACTION_PING_API === ($form_state->getTriggeringElement()['#name'] ?? NULL)) { + try { + $this->helper->pingApi(); + $this->messenger()->addStatus($this->t('Pinged API successfully.')); } - else { - $this->messenger()->addStatus($this->t('Settings succesfully tested')); + catch (\Throwable $t) { + $this->messenger()->addError($this->t('Pinging API failed: @message', ['@message' => $t->getMessage()])); } + return; } - catch (\Throwable $throwable) { - $message = $this->t('Error testing provided information: %message', ['%message' => $throwable->getMessage()]); - $this->messenger()->addError($message); + + $config = $this->config(self::CONFIG_NAME); + foreach ([ + self::KEY, + self::GET_ORGANIZED_BASE_URL, + ] as $key) { + $config->set($key, $form_state->getValue($key)); } + $config->save(); + + parent::submitForm($form, $form_state); } } diff --git a/src/Helper/ArchiveHelper.php b/src/Helper/ArchiveHelper.php index 4ca466f..e641741 100644 --- a/src/Helper/ArchiveHelper.php +++ b/src/Helper/ArchiveHelper.php @@ -12,9 +12,13 @@ use Drupal\webform\Entity\WebformSubmission; use Drupal\webform_attachment\Element\WebformAttachmentBase; use ItkDev\GetOrganized\Client; +use ItkDev\GetOrganized\ClientInterface; use ItkDev\GetOrganized\Service\Cases; use ItkDev\GetOrganized\Service\Documents; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpClient\Exception\ClientException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; /** * Helper for archiving documents in GetOrganized. @@ -91,20 +95,15 @@ public function __construct(EntityTypeManagerInterface $entityTypeManager, Event * @phpstan-param array $handlerConfiguration */ public function archive(string $submissionId, array $handlerConfiguration): void { - // Setup Client and services. - if (NULL === $this->client) { - $this->setupClient(); - } - if (NULL === $this->caseService) { /** @var \ItkDev\GetOrganized\Service\Cases $caseService */ - $caseService = $this->client->api('cases'); + $caseService = $this->client()->api('cases'); $this->caseService = $caseService; } if (NULL === $this->documentService) { /** @var \ItkDev\GetOrganized\Service\Documents $docService */ - $docService = $this->client->api('documents'); + $docService = $this->client()->api('documents'); $this->documentService = $docService; } @@ -117,18 +116,44 @@ public function archive(string $submissionId, array $handlerConfiguration): void elseif ('archive_to_citizen' === $archivingMethod) { $this->archiveToCitizen($submissionId, $handlerConfiguration); } + } + /** + * Ping the Get Organized API. + * + * Interpret a 400 Bad Request response as a success. + * + * @throws \Throwable + */ + public function pingApi(): void { + try { + /** @var \ItkDev\GetOrganized\Service\Documents $service */ + $service = $this->client()->api('documents'); + $request = new \ReflectionMethod($service, 'request'); + $request->invoke($service, Request::METHOD_GET, '/'); + } + catch (\Throwable $t) { + // Throw if it's not a 400 Bad Request exception. + if (!($t instanceof ClientException) + || Response::HTTP_BAD_REQUEST !== $t->getCode()) { + throw $t; + } + } } /** * Sets up Client. */ - private function setupClient(): void { - $username = $this->settings->getUsername(); - $password = $this->settings->getPassword(); - $baseUrl = $this->settings->getBaseUrl(); + private function client(): ClientInterface { + if (NULL === $this->client) { + $username = $this->settings->getUsername(); + $password = $this->settings->getPassword(); + $baseUrl = $this->settings->getBaseUrl(); - $this->client = new Client($username, $password, $baseUrl); + $this->client = new Client($username, $password, $baseUrl); + } + + return $this->client; } /** @@ -177,9 +202,6 @@ private function archiveToCitizen(string $submissionId, array $handlerConfigurat // Step 1: Find/create parent case // Step 2: Find/create subcase // Step 3: Upload to subcase. - if (NULL === $this->client) { - $this->setupClient(); - } /** @var \Drupal\webform\Entity\WebformSubmission $submission */ $submission = $this->getSubmission($submissionId); diff --git a/src/Helper/Settings.php b/src/Helper/Settings.php index 579b287..5f46ecf 100644 --- a/src/Helper/Settings.php +++ b/src/Helper/Settings.php @@ -2,80 +2,101 @@ namespace Drupal\os2forms_get_organized\Helper; -use Drupal\Core\KeyValueStore\KeyValueFactoryInterface; -use Drupal\Core\KeyValueStore\KeyValueStoreInterface; -use Drupal\os2forms_get_organized\Exception\InvalidSettingException; +use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Config\ImmutableConfig; +use Drupal\key\KeyRepositoryInterface; use Drupal\os2forms_get_organized\Form\SettingsForm; -use Symfony\Component\OptionsResolver\OptionsResolver; /** * General settings for os2forms_get_organized. */ class Settings { /** - * The store. + * The config. * - * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface + * @var \Drupal\Core\Config\ImmutableConfig */ - private KeyValueStoreInterface $store; + private ImmutableConfig $config; /** - * The key value collection name. - * - * @var string + * The constructor. */ - private $collection = 'os2forms_get_organized'; + public function __construct( + ConfigFactoryInterface $configFactory, + private readonly KeyRepositoryInterface $keyRepository, + ) { + $this->config = $configFactory->get(SettingsForm::CONFIG_NAME); + } /** - * Default setting values. - * - * @var array - * @phpstan-var array + * Get key. */ - private $defaultSettings = [ - SettingsForm::GET_ORGANIZED_USERNAME => '', - SettingsForm::GET_ORGANIZED_PASSWORD => '', - SettingsForm::GET_ORGANIZED_BASE_URL => '', - ]; + public function getKey(): ?string { + return $this->get(SettingsForm::KEY); + } /** - * Constructor. + * Get password. + * + * @return string + * The sources. */ - public function __construct(KeyValueFactoryInterface $keyValueFactory) { - $this->store = $keyValueFactory->get($this->collection); + public function getBaseUrl(): string { + $value = $this->get(SettingsForm::GET_ORGANIZED_BASE_URL); + return is_string($value) ? $value : ''; } /** * Get username. * * @return string - * The sources. */ public function getUsername(): string { - $value = $this->get(SettingsForm::GET_ORGANIZED_USERNAME); - return is_string($value) ? $value : ''; + return $this->getKeyValue('username'); } /** * Get password. * * @return string - * The sources. */ public function getPassword(): string { - $value = $this->get(SettingsForm::GET_ORGANIZED_PASSWORD); - return is_string($value) ? $value : ''; + return $this->getKeyValue('password'); } /** - * Get password. + * Get key value. * - * @return string - * The sources. + * @param string $name + * The value name. + * + * @return null|string + * The value if any. */ - public function getBaseUrl(): string { - $value = $this->get(SettingsForm::GET_ORGANIZED_BASE_URL); - return is_string($value) ? $value : ''; + private function getKeyValue(string $name): ?string { + $key = $this->keyRepository->getKey( + $this->getKey() + ); + + try { + $values = json_decode($key?->getKeyValue() ?? '{}', TRUE, 512, JSON_THROW_ON_ERROR); + + return $values[$name] ?? NULL; + } + catch (\Throwable $exception) { + return NULL; + } + } + + /** + * Get certificate. + */ + public function getCertificate(): ?string { + $key = $this->keyRepository->getKey( + $this->getKey(), + ); + + return $key?->getKeyValue(); } /** @@ -90,44 +111,7 @@ public function getBaseUrl(): string { * The setting value. */ private function get(string $key, mixed $default = NULL): mixed { - $resolver = $this->getSettingsResolver(); - if (!$resolver->isDefined($key)) { - throw new InvalidSettingException(sprintf('Setting %s is not defined', $key)); - } - - return $this->store->get($key, $default); - } - - /** - * Set settings. - * - * @throws \Symfony\Component\OptionsResolver\Exception\ExceptionInterface - * - * @phpstan-param array $settings - */ - public function setSettings(array $settings): self { - $settings = $this->getSettingsResolver()->resolve($settings); - foreach ($settings as $key => $value) { - $this->store->set($key, $value); - } - - return $this; - } - - /** - * Get settings resolver. - */ - private function getSettingsResolver(): OptionsResolver { - return (new OptionsResolver()) - ->setDefaults($this->defaultSettings) - ->setAllowedTypes(SettingsForm::GET_ORGANIZED_USERNAME, 'string') - ->setAllowedTypes(SettingsForm::GET_ORGANIZED_PASSWORD, 'string') - ->setAllowedTypes(SettingsForm::GET_ORGANIZED_BASE_URL, 'string') - ->setRequired([ - SettingsForm::GET_ORGANIZED_USERNAME, - SettingsForm::GET_ORGANIZED_PASSWORD, - SettingsForm::GET_ORGANIZED_BASE_URL, - ]); + return $this->config->get($key) ?? $default; } } diff --git a/src/Plugin/AdvancedQueue/JobType/ArchiveDocument.php b/src/Plugin/AdvancedQueue/JobType/ArchiveDocument.php index d81553c..9b5a2ae 100644 --- a/src/Plugin/AdvancedQueue/JobType/ArchiveDocument.php +++ b/src/Plugin/AdvancedQueue/JobType/ArchiveDocument.php @@ -60,7 +60,7 @@ public function __construct( $plugin_id, $plugin_definition, ArchiveHelper $helper, - LoggerChannelFactoryInterface $loggerFactory + LoggerChannelFactoryInterface $loggerFactory, ) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->helper = $helper;