From 0d40a1ddcd906d966796b6bf9209f079e1e702a6 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Thu, 5 Dec 2024 09:15:50 +0200 Subject: [PATCH 01/15] UHF-10539: Make redirect entities publishable --- helfi_platform_config.install | 49 +++++++++++++ helfi_platform_config.module | 15 ++++ src/Entity/PublishableRedirect.php | 27 +++++++ tests/src/Kernel/RedirectEntityTest.php | 95 +++++++++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 src/Entity/PublishableRedirect.php create mode 100644 tests/src/Kernel/RedirectEntityTest.php diff --git a/helfi_platform_config.install b/helfi_platform_config.install index 0ebaa74d8..320a3e84a 100644 --- a/helfi_platform_config.install +++ b/helfi_platform_config.install @@ -5,6 +5,10 @@ * Contains installation hooks for HELfi platform config module. */ +use Drupal\Core\Entity\EntityStorageException; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\helfi_platform_config\Entity\PublishableRedirect; use Drupal\user\Entity\User; /** @@ -215,3 +219,48 @@ function helfi_platform_config_update_9314() : void { $config_factory->getEditable('block.block.hdbt_subtheme_user_inquiry')->delete(); } } + +/** + * UHF-10539: Update redirect entity type. + */ +function helfi_platform_config_update_9315() : void { + if (!\Drupal::moduleHandler()->moduleExists('redirect')) { + return; + } + + $updateManager = \Drupal::entityDefinitionUpdateManager(); + $entityTypes = [ + 'redirect' => $updateManager->getEntityType('redirect'), + ]; + + helfi_platform_config_entity_type_build($entityTypes); + + /** @var \Drupal\Core\Entity\EntityTypeInterface $entityType */ + $entityType = reset($entityTypes); + + // Alter field definition so that NULL values are allowed. + $fields = PublishableRedirect::publishedBaseFieldDefinitions($entityType); + $field = reset($fields); + $field->setInitialValue(TRUE); + + // Revert class change: + $entityType->setClass($entityType->getOriginalClass()); + + // Update entity settings without updating the class. + $updateManager->updateEntityType($entityType); + + $updateManager->installFieldStorageDefinition( + $entityType->getKey('published'), + $entityType->id(), + 'helfi_platform_config', + $field + ); + + helfi_platform_config_entity_type_build($entityTypes); + + /** @var \Drupal\Core\Entity\EntityTypeInterface $entityType */ + $entityType = reset($entityTypes); + + // Update entity type again with class change. + $updateManager->updateEntityType($entityType); +} diff --git a/helfi_platform_config.module b/helfi_platform_config.module index be48b6271..0c02d35a2 100644 --- a/helfi_platform_config.module +++ b/helfi_platform_config.module @@ -12,6 +12,7 @@ use Drupal\Core\Breadcrumb\Breadcrumb; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityPublishedInterface; +use Drupal\Core\Entity\EntityTypeManager; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\FieldConfigBase; use Drupal\Core\Language\LanguageInterface; @@ -22,10 +23,24 @@ use Drupal\Core\Url; use Drupal\block\Entity\Block; use Drupal\helfi_api_base\Environment\Project; use Drupal\helfi_platform_config\DTO\ParagraphTypeCollection; +use Drupal\helfi_platform_config\Entity\PublishableRedirect; use Drupal\helfi_platform_config\EntityVersionMatcher; use Drupal\paragraphs\Entity\ParagraphsType; use Drupal\user\Entity\Role; +/** + * Implements hook_entity_type_build(). + * + * @param \Drupal\Core\Entity\EntityTypeInterface[] &$entity_types + * Entity types. + */ +function helfi_platform_config_entity_type_build(array &$entity_types): void { + if (isset($entity_types['redirect'])) { + $entity_types['redirect']->setClass(PublishableRedirect::class); + $entity_types['redirect']->set('entity_keys', $entity_types['redirect']->getKeys() + ['published' => 'status']); + } +} + /** * Implements hook_modules_installed(). */ diff --git a/src/Entity/PublishableRedirect.php b/src/Entity/PublishableRedirect.php new file mode 100644 index 000000000..948838f0c --- /dev/null +++ b/src/Entity/PublishableRedirect.php @@ -0,0 +1,27 @@ +installEntitySchema('path_alias'); + $this->installEntitySchema('redirect'); + } + + /** + * Tests publishable redirect. + */ + public function testPublishableRedirect(): void { + $storage = $this->container->get(EntityTypeManagerInterface::class) + ->getStorage('redirect'); + + $entityClass = $storage->getEntityClass(); + $reflection = new \ReflectionClass($entityClass); + + $this->assertTrue($reflection->implementsInterface(EntityPublishedInterface::class)); + + $redirect = $storage->create(); + + $this->assertInstanceOf(PublishableRedirect::class, $redirect); + + $redirect->setSource('internal:/source'); + $redirect->setRedirect('internal:/destination'); + $redirect->setStatusCode(300); + $redirect->save(); + + // Published by default. + $this->assertTrue($redirect->isPublished()); + } + + /** + * Tests that auto redirect works. + * + * @see \redirect_path_alias_update() + */ + public function testAutoRedirect(): void { + $this->config('redirect.settings') + ->set('auto_redirect', TRUE) + ->save(); + + $pathAlias = PathAlias::create([ + 'path' => '/unaliased/path', + 'alias' => '/aliased/path/old', + ]); + $pathAlias->save(); + $pathAlias->setAlias('/aliased/path/new'); + $pathAlias->save(); + + $storage = $this->container->get(EntityTypeManagerInterface::class) + ->getStorage('redirect'); + + $redirects = $storage->loadByProperties([ + 'status' => 1, + ]); + + // Redirect should be created when path alias is updated. + $this->assertNotEmpty($redirects); + } + +} From f1938d7994c69d2f2e4fdc27cfe5304dceedcbe8 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Thu, 5 Dec 2024 09:16:01 +0200 Subject: [PATCH 02/15] UHF-10539: Add PublishableRedirectRepository --- src/HelfiPlatformConfigServiceProvider.php | 6 ++++ src/PublishableRedirectRepository.php | 36 ++++++++++++++++++++++ tests/src/Kernel/RedirectEntityTest.php | 20 ++++++++++-- 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 src/PublishableRedirectRepository.php diff --git a/src/HelfiPlatformConfigServiceProvider.php b/src/HelfiPlatformConfigServiceProvider.php index 5a12ea8cb..3bfcca16b 100644 --- a/src/HelfiPlatformConfigServiceProvider.php +++ b/src/HelfiPlatformConfigServiceProvider.php @@ -23,6 +23,12 @@ public function alter(ContainerBuilder $container) : void { $definition = $container->getDefinition('config_rewrite.config_rewriter'); $definition->setClass(ConfigRewriter::class); } + + // Support publishable redirects. + if ($container->hasDefinition('redirect.repository')) { + $definition = $container->getDefinition('redirect.repository'); + $definition->setClass(PublishableRedirectRepository::class); + } } } diff --git a/src/PublishableRedirectRepository.php b/src/PublishableRedirectRepository.php new file mode 100644 index 000000000..aaf0fe670 --- /dev/null +++ b/src/PublishableRedirectRepository.php @@ -0,0 +1,36 @@ +isPublished()) { + return NULL; + } + } + + return $redirect; + } + +} diff --git a/tests/src/Kernel/RedirectEntityTest.php b/tests/src/Kernel/RedirectEntityTest.php index d1a30df57..2a6bc6792 100644 --- a/tests/src/Kernel/RedirectEntityTest.php +++ b/tests/src/Kernel/RedirectEntityTest.php @@ -7,6 +7,7 @@ use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\helfi_platform_config\Entity\PublishableRedirect; +use Drupal\helfi_platform_config\PublishableRedirectRepository; use Drupal\KernelTests\KernelTestBase; use Drupal\path_alias\Entity\PathAlias; @@ -54,13 +55,26 @@ public function testPublishableRedirect(): void { $this->assertInstanceOf(PublishableRedirect::class, $redirect); - $redirect->setSource('internal:/source'); - $redirect->setRedirect('internal:/destination'); + $redirect->setSource('/source'); + $redirect->setRedirect('/destination'); $redirect->setStatusCode(300); $redirect->save(); // Published by default. $this->assertTrue($redirect->isPublished()); + + $repository = $this->container->get('redirect.repository'); + $this->assertInstanceOf(PublishableRedirectRepository::class, $repository); + + $match = $repository->findMatchingRedirect('/source', language: $redirect->language()->getId()); + $this->assertNotEmpty($match); + + // Unpublishing redirect should remove it from findMatchingRedirect. + $redirect->setUnpublished(); + $redirect->save(); + + $match = $repository->findMatchingRedirect('/source', language: $redirect->language()->getId()); + $this->assertEmpty($match); } /** @@ -88,7 +102,7 @@ public function testAutoRedirect(): void { 'status' => 1, ]); - // Redirect should be created when path alias is updated. + // One redirect should be created when path alias is updated. $this->assertNotEmpty($redirects); } From d7c4ee4330853d565e61b7421d8e539ae7363c88 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Thu, 5 Dec 2024 09:16:03 +0200 Subject: [PATCH 03/15] Add is_custom field to redirect --- helfi_platform_config.install | 28 +++++---- helfi_platform_config.module | 19 +++++- src/Entity/PublishableRedirect.php | 16 +++++ tests/src/Functional/RedirectFormTest.php | 71 +++++++++++++++++++++++ tests/src/Kernel/RedirectEntityTest.php | 3 + 5 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 tests/src/Functional/RedirectFormTest.php diff --git a/helfi_platform_config.install b/helfi_platform_config.install index 320a3e84a..089fd896d 100644 --- a/helfi_platform_config.install +++ b/helfi_platform_config.install @@ -238,29 +238,33 @@ function helfi_platform_config_update_9315() : void { /** @var \Drupal\Core\Entity\EntityTypeInterface $entityType */ $entityType = reset($entityTypes); - // Alter field definition so that NULL values are allowed. - $fields = PublishableRedirect::publishedBaseFieldDefinitions($entityType); - $field = reset($fields); - $field->setInitialValue(TRUE); + $fields = PublishableRedirect::baseFieldDefinitions($entityType); - // Revert class change: + // Revert class change. $entityType->setClass($entityType->getOriginalClass()); // Update entity settings without updating the class. $updateManager->updateEntityType($entityType); - $updateManager->installFieldStorageDefinition( - $entityType->getKey('published'), - $entityType->id(), - 'helfi_platform_config', - $field - ); + foreach (['published', 'custom'] as $key) { + $field = $fields[$entityType->getKey($key)]; + + // Set published and custom initially to TRUE. + $field->setInitialValue(TRUE); + + $updateManager->installFieldStorageDefinition( + $entityType->getKey($key), + $entityType->id(), + 'helfi_platform_config', + $field + ); + } helfi_platform_config_entity_type_build($entityTypes); /** @var \Drupal\Core\Entity\EntityTypeInterface $entityType */ $entityType = reset($entityTypes); - // Update entity type again with class change. + // Update entity type again with the class change. $updateManager->updateEntityType($entityType); } diff --git a/helfi_platform_config.module b/helfi_platform_config.module index 0c02d35a2..3da4ed96b 100644 --- a/helfi_platform_config.module +++ b/helfi_platform_config.module @@ -15,6 +15,7 @@ use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\EntityTypeManager; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\FieldConfigBase; +use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Link; use Drupal\Core\Routing\RouteMatchInterface; @@ -37,7 +38,10 @@ use Drupal\user\Entity\Role; function helfi_platform_config_entity_type_build(array &$entity_types): void { if (isset($entity_types['redirect'])) { $entity_types['redirect']->setClass(PublishableRedirect::class); - $entity_types['redirect']->set('entity_keys', $entity_types['redirect']->getKeys() + ['published' => 'status']); + $entity_types['redirect']->set('entity_keys', $entity_types['redirect']->getKeys() + [ + 'published' => 'status', + 'custom' => 'is_custom', + ]); } } @@ -520,3 +524,16 @@ function helfi_platform_config_config_schema_info_alter(array &$definitions) : v $definitions['social_media.item.email']['mapping']['text']['translation context'] = 'Social media: email'; } } + +/** + * Implements hook_form_BASE_FORM_ID_alter(). + */ +function helfi_platform_config_form_redirect_redirect_form_alter(&$form, FormStateInterface $form_state, $form_id): void { + // Set is_custom field to true whenever redirect entity is saved from + // entity form. The field defaults to FALSE if it is saved from Drupal API. + $form['is_custom'] = [ + '#type' => 'hidden', + '#access' => FALSE, + '#default_value' => [TRUE], + ]; +} diff --git a/src/Entity/PublishableRedirect.php b/src/Entity/PublishableRedirect.php index 948838f0c..e6808a63f 100644 --- a/src/Entity/PublishableRedirect.php +++ b/src/Entity/PublishableRedirect.php @@ -5,6 +5,8 @@ use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Entity\EntityPublishedTrait; use Drupal\Core\Entity\EntityTypeInterface; +use Drupal\Core\Field\BaseFieldDefinition; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\redirect\Entity\Redirect; /** @@ -21,7 +23,21 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type): a $fields = parent::baseFieldDefinitions($entity_type); $fields += self::publishedBaseFieldDefinitions($entity_type); + $fields[$entity_type->getKey('custom')] = BaseFieldDefinition::create('boolean') + ->setLabel(new TranslatableMarkup('Custom redirect')) + ->setDefaultValue(FALSE); + return $fields; } + /** + * Is custom redirect. + * + * @return bool + * FALSE if this redirect was created automatically by Drupal. + */ + public function isCustom(): bool { + return !!$this->getEntityKey('custom'); + } + } diff --git a/tests/src/Functional/RedirectFormTest.php b/tests/src/Functional/RedirectFormTest.php new file mode 100644 index 000000000..c2b36292e --- /dev/null +++ b/tests/src/Functional/RedirectFormTest.php @@ -0,0 +1,71 @@ +createUser([ + 'administer redirects', + ]); + $this->drupalLogin($user); + } + + /** + * Tests that saving redirect from entity form sets the custom field to TRUE. + */ + public function testRedirectForm() { + $edit = [ + 'redirect_source[0][path]' => 'test', + 'redirect_redirect[0][uri]' => '', + 'status_code' => 307, + ]; + + $this->drupalGet(Url::fromRoute('redirect.add')->toString()); + $this->submitForm($edit, 'Save'); + + $redirects = $this->container + ->get(EntityTypeManagerInterface::class) + ->getStorage('redirect') + ->loadByProperties([ + 'redirect_source' => 'test', + ]); + + $this->assertNotEmpty($redirects); + $redirect = reset($redirects); + $this->assertInstanceOf(PublishableRedirect::class, $redirect); + + // Redirect created from entity form should be marked as custom. + $this->assertTrue($redirect->isCustom()); + } + +} diff --git a/tests/src/Kernel/RedirectEntityTest.php b/tests/src/Kernel/RedirectEntityTest.php index 2a6bc6792..484da28b8 100644 --- a/tests/src/Kernel/RedirectEntityTest.php +++ b/tests/src/Kernel/RedirectEntityTest.php @@ -63,6 +63,9 @@ public function testPublishableRedirect(): void { // Published by default. $this->assertTrue($redirect->isPublished()); + // Generated with API => should not be custom. + $this->assertFalse($redirect->isCustom()); + $repository = $this->container->get('redirect.repository'); $this->assertInstanceOf(PublishableRedirectRepository::class, $repository); From 09e89076784131689609bbd491d84ba131e3e58c Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Thu, 5 Dec 2024 09:16:04 +0200 Subject: [PATCH 04/15] Add RedirectCleaner --- .../schema/helfi_platform_config.schema.yml | 6 ++ helfi_platform_config.install | 5 +- helfi_platform_config.module | 43 ++++++---- helfi_platform_config.services.yml | 3 + src/RedirectCleaner.php | 84 +++++++++++++++++++ tests/src/Functional/RedirectFormTest.php | 2 + tests/src/Kernel/RedirectEntityTest.php | 55 ++++++++++++ 7 files changed, 181 insertions(+), 17 deletions(-) create mode 100644 src/RedirectCleaner.php diff --git a/config/schema/helfi_platform_config.schema.yml b/config/schema/helfi_platform_config.schema.yml index 0f2e00c2b..2d5bb7b1d 100644 --- a/config/schema/helfi_platform_config.schema.yml +++ b/config/schema/helfi_platform_config.schema.yml @@ -17,6 +17,12 @@ block.settings.telia_ace_widget: type: text label: 'Chat button label' +helfi_platform_config.redirect_cleaner: + type: config_object + label: 'Redirect cleaner' + mapping: + enable: + type: boolean # Default value. field.value.location: diff --git a/helfi_platform_config.install b/helfi_platform_config.install index 089fd896d..5fdac1aee 100644 --- a/helfi_platform_config.install +++ b/helfi_platform_config.install @@ -5,9 +5,8 @@ * Contains installation hooks for HELfi platform config module. */ -use Drupal\Core\Entity\EntityStorageException; -use Drupal\Core\Field\BaseFieldDefinition; -use Drupal\Core\StringTranslation\TranslatableMarkup; +declare(strict_types=1); + use Drupal\helfi_platform_config\Entity\PublishableRedirect; use Drupal\user\Entity\User; diff --git a/helfi_platform_config.module b/helfi_platform_config.module index 3da4ed96b..db39b15c0 100644 --- a/helfi_platform_config.module +++ b/helfi_platform_config.module @@ -12,7 +12,6 @@ use Drupal\Core\Breadcrumb\Breadcrumb; use Drupal\Core\Entity\ContentEntityInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityPublishedInterface; -use Drupal\Core\Entity\EntityTypeManager; use Drupal\Core\Field\BaseFieldDefinition; use Drupal\Core\Field\FieldConfigBase; use Drupal\Core\Form\FormStateInterface; @@ -20,20 +19,19 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Link; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Session\AccountInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; use Drupal\block\Entity\Block; use Drupal\helfi_api_base\Environment\Project; use Drupal\helfi_platform_config\DTO\ParagraphTypeCollection; -use Drupal\helfi_platform_config\Entity\PublishableRedirect; use Drupal\helfi_platform_config\EntityVersionMatcher; +use Drupal\helfi_platform_config\Entity\PublishableRedirect; +use Drupal\helfi_platform_config\RedirectCleaner; use Drupal\paragraphs\Entity\ParagraphsType; use Drupal\user\Entity\Role; /** * Implements hook_entity_type_build(). - * - * @param \Drupal\Core\Entity\EntityTypeInterface[] &$entity_types - * Entity types. */ function helfi_platform_config_entity_type_build(array &$entity_types): void { if (isset($entity_types['redirect'])) { @@ -526,14 +524,31 @@ function helfi_platform_config_config_schema_info_alter(array &$definitions) : v } /** - * Implements hook_form_BASE_FORM_ID_alter(). + * Implements hook_form_alter(). */ -function helfi_platform_config_form_redirect_redirect_form_alter(&$form, FormStateInterface $form_state, $form_id): void { - // Set is_custom field to true whenever redirect entity is saved from - // entity form. The field defaults to FALSE if it is saved from Drupal API. - $form['is_custom'] = [ - '#type' => 'hidden', - '#access' => FALSE, - '#default_value' => [TRUE], - ]; +function helfi_platform_config_form_alter(&$form, FormStateInterface $form_state, $form_id): void { + if (in_array($form_id, ['redirect_redirect_edit_form', 'redirect_redirect_form'])) { + // Set is_custom field to true whenever redirect entity is saved from + // entity form. The field defaults to FALSE if it is saved from Drupal API. + $form['is_custom'] = [ + '#type' => 'hidden', + '#access' => FALSE, + '#default_value' => [TRUE], + ]; + + $form['status'] = [ + '#type' => 'checkbox', + '#title' => new TranslatableMarkup('Published'), + '#default_value' => TRUE, + ]; + } +} + +/** + * Implements hook_cron(). + */ +function helfi_platform_config_cron(): void { + /** @var \Drupal\helfi_platform_config\RedirectCleaner $cleaner */ + $cleaner = \Drupal::service(RedirectCleaner::class); + $cleaner->unpublishExpiredRedirects(); } diff --git a/helfi_platform_config.services.yml b/helfi_platform_config.services.yml index 514508ea3..d4a149b7f 100644 --- a/helfi_platform_config.services.yml +++ b/helfi_platform_config.services.yml @@ -1,6 +1,7 @@ services: _defaults: autoconfigure: true + autowire: true Drupal\helfi_platform_config\Helper\BlockInstaller: '@helfi_platform_config.helper.block_installer' helfi_platform_config.helper.block_installer: @@ -79,3 +80,5 @@ services: - '@file_url_generator' tags: - { name: helfi_platform_config.og_image_builder, priority: -100 } + + Drupal\helfi_platform_config\RedirectCleaner: ~ diff --git a/src/RedirectCleaner.php b/src/RedirectCleaner.php new file mode 100644 index 000000000..442380e5d --- /dev/null +++ b/src/RedirectCleaner.php @@ -0,0 +1,84 @@ +configuration = $configFactory->get('helfi_platform_config.redirect_cleaner')->get(); + } + + /** + * Return TRUE if this feature is enabled. + */ + public function isEnabled(): bool { + return $this->configuration['enable'] ?? FALSE; + } + + /** + * Unpublish expired redirects. + */ + public function unpublishExpiredRedirects(): void { + if (!$this->isEnabled()) { + return; + } + + try { + $storage = $this->entityTypeManager->getStorage('redirect'); + } + catch (PluginNotFoundException | InvalidPluginDefinitionException) { + // Redirect module most likely not installed. + return; + } + + $entityType = $storage->getEntityType(); + + $query = $storage->getQuery() + ->accessCheck(FALSE) + // Search only published redirects. + ->condition($entityType->getKey('published'), 1) + // That are not custom. + ->condition($entityType->getKey('custom'), 0) + // And expired. + ->condition('created', strtotime('-6 months'), '<') + // Query should have some limit. + ->range(0, 50); + + foreach ($query->execute() as $id) { + $redirect = $storage->load($id); + if ($redirect instanceof PublishableRedirect) { + $this->logger->info('Unpublishing redirect: %id', ['%id' => $redirect->id()]); + + $redirect->setUnpublished(); + $redirect->save(); + } + } + } + +} diff --git a/tests/src/Functional/RedirectFormTest.php b/tests/src/Functional/RedirectFormTest.php index c2b36292e..9bf99baf0 100644 --- a/tests/src/Functional/RedirectFormTest.php +++ b/tests/src/Functional/RedirectFormTest.php @@ -1,5 +1,7 @@ assertNotEmpty($redirects); } + /** + * Tests redirect cleaner. + */ + public function testRedirectCleaner(): void { + $storage = $this->container->get(EntityTypeManagerInterface::class) + ->getStorage('redirect'); + + $tests = [ + [ + 'status' => 1, + 'is_custom' => 1, + 'created' => strtotime('-1 year'), + ], + [ + 'status' => 1, + 'is_custom' => 0, + 'created' => strtotime('-1 year'), + ], + [ + 'status' => 1, + 'is_custom' => 0, + 'created' => strtotime('now'), + ], + ]; + + foreach ($tests as $id => $test) { + $redirect = $storage->create([ + 'redirect_source' => "source/$id", + 'redirect_redirect' => '/destination', + 'status_code' => 301, + ] + $test); + + $redirect->save(); + } + + // Enable the service. + $this->config('helfi_platform_config.redirect_cleaner')->set('enable', TRUE)->save(); + + $cleaner = $this->container->get(RedirectCleaner::class); + $cleaner->unpublishExpiredRedirects(); + + foreach ($tests as $id => $test) { + $redirects = $storage->loadByProperties(['redirect_source' => "source/$id"]); + $redirect = reset($redirects); + + $this->assertInstanceOf(EntityPublishedInterface::class, $redirect); + + $this->assertEquals( + $test['is_custom'] || $test['created'] > strtotime('-6 months'), + $redirect->isPublished() + ); + } + } + } From 61c2e24e6de8f4de004963b18853b9fa20d753b2 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Thu, 5 Dec 2024 09:16:05 +0200 Subject: [PATCH 05/15] Add iews.view.redirect --- .../config/install/views.view.redirect.yml | 782 ++++++++++++++++++ .../language/fi/views.view.redirect.yml | 60 ++ .../helfi_base_content.install | 8 + 3 files changed, 850 insertions(+) create mode 100644 modules/helfi_base_content/config/install/views.view.redirect.yml create mode 100644 modules/helfi_base_content/config/optional/language/fi/views.view.redirect.yml diff --git a/modules/helfi_base_content/config/install/views.view.redirect.yml b/modules/helfi_base_content/config/install/views.view.redirect.yml new file mode 100644 index 000000000..b9d4ed761 --- /dev/null +++ b/modules/helfi_base_content/config/install/views.view.redirect.yml @@ -0,0 +1,782 @@ +uuid: 30410398-1ba2-4548-aa8a-4c99cb8b82b4 +langcode: en +status: true +dependencies: + config: + - system.menu.admin + module: + - link + - redirect + - user +id: redirect +label: Redirect +module: views +description: 'List of redirects' +tag: '' +base_table: redirect +base_field: rid +display: + default: + id: default + display_title: Master + display_plugin: default + position: 0 + display_options: + title: Redirect + fields: + redirect_bulk_form: + id: redirect_bulk_form + table: redirect + field: redirect_bulk_form + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + plugin_id: redirect_bulk_form + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + action_title: 'With selection' + include_exclude: exclude + selected_actions: { } + redirect_source__path: + id: redirect_source__path + table: redirect + field: redirect_source__path + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + entity_field: redirect_source + plugin_id: field + label: From + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: path + type: redirect_source + settings: { } + group_column: '' + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + redirect_redirect__uri: + id: redirect_redirect__uri + table: redirect + field: redirect_redirect__uri + entity_type: redirect + entity_field: redirect_redirect + plugin_id: field + status_code: + id: status_code + table: redirect + field: status_code + entity_type: redirect + entity_field: status_code + plugin_id: field + is_custom: + id: is_custom + table: redirect + field: is_custom + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + entity_field: is_custom + plugin_id: field + label: Custom + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: unicode-yes-no + format_custom_false: '' + format_custom_true: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + language: + id: language + table: redirect + field: language + entity_type: redirect + entity_field: language + plugin_id: field + created: + id: created + table: redirect + field: created + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + entity_field: created + plugin_id: date + label: Created + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + date_format: fallback + custom_date_format: '' + timezone: '' + operations: + id: operations + table: redirect + field: operations + entity_type: redirect + plugin_id: entity_operations + pager: + type: full + options: + offset: 0 + pagination_heading_level: h4 + items_per_page: 50 + total_pages: null + id: 0 + tags: + next: 'next ›' + previous: '‹ previous' + first: '« first' + last: 'last »' + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + quantity: 9 + exposed_form: + type: basic + options: + submit_button: Filter + reset_button: true + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + access: + type: perm + options: + perm: 'administer redirects' + cache: + type: tag + options: { } + empty: + area_text_custom: + id: area_text_custom + table: views + field: area_text_custom + relationship: none + group_type: group + admin_label: '' + plugin_id: text_custom + empty: true + content: 'There is no redirect yet.' + tokenize: false + sorts: { } + arguments: { } + filters: + redirect_source__path: + id: redirect_source__path + table: redirect + field: redirect_source__path + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + entity_field: redirect_source + plugin_id: string + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: redirect_source__path_op + label: From + description: '' + use_operator: false + operator: redirect_source__path_op + operator_limit_selection: false + operator_list: { } + identifier: redirect_source__path + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + redirect_redirect__uri: + id: redirect_redirect__uri + table: redirect + field: redirect_redirect__uri + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + entity_field: redirect_redirect + plugin_id: string + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: redirect_redirect__uri_op + label: To + description: '' + use_operator: false + operator: redirect_redirect__uri_op + operator_limit_selection: false + operator_list: { } + identifier: redirect_redirect__uri + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + status_code: + id: status_code + table: redirect + field: status_code + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + entity_field: status_code + plugin_id: numeric + operator: '=' + value: + min: '' + max: '' + value: '' + group: 1 + exposed: true + expose: + operator_id: status_code_op + label: 'Status code' + description: '' + use_operator: false + operator: status_code_op + operator_limit_selection: false + operator_list: { } + identifier: status_code + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: true + group_info: + label: 'Status code' + description: '' + identifier: status_code + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: + 1: + title: '300 Multiple Choices' + operator: '=' + value: + min: '' + max: '' + value: '300' + 2: + title: '301 Moved Permanently' + operator: '=' + value: + min: '' + max: '' + value: '301' + 3: + title: '302 Found' + operator: '=' + value: + min: '' + max: '' + value: '302' + 4: + title: '303 See Other' + operator: '=' + value: + min: '' + max: '' + value: '303' + 5: + title: '304 Not Modified' + operator: '=' + value: + min: '' + max: '' + value: '304' + 6: + title: '305 Use Proxy' + operator: '=' + value: + min: '' + max: '' + value: '305' + 7: + title: '307 Temporary Redirect' + operator: '=' + value: + min: '' + max: '' + value: '307' + language: + id: language + table: redirect + field: language + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + entity_field: language + plugin_id: language + operator: in + value: { } + group: 1 + exposed: true + expose: + operator_id: language_op + label: 'Original language' + description: '' + use_operator: false + operator: language_op + operator_limit_selection: false + operator_list: { } + identifier: language + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + reduce: false + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + is_custom: + id: is_custom + table: redirect + field: is_custom + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + entity_field: is_custom + plugin_id: boolean + operator: '=' + value: All + group: 1 + exposed: true + expose: + operator_id: '' + label: Custom + description: '' + use_operator: false + operator: is_custom_op + operator_limit_selection: false + operator_list: { } + identifier: is_custom + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + read_only: '0' + content_producer: '0' + editor: '0' + admin: '0' + menu_api: '0' + super_administrator: '0' + news_producer: '0' + survey_editor: '0' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + status: + id: status + table: redirect + field: status + relationship: none + group_type: group + admin_label: '' + entity_type: redirect + entity_field: status + plugin_id: boolean + operator: '=' + value: '1' + group: 1 + exposed: true + expose: + operator_id: '' + label: Julkaistu + description: '' + use_operator: false + operator: status_op + operator_limit_selection: false + operator_list: { } + identifier: status + required: true + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + read_only: '0' + content_producer: '0' + editor: '0' + admin: '0' + menu_api: '0' + super_administrator: '0' + news_producer: '0' + survey_editor: '0' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + filter_groups: + operator: AND + groups: + 1: AND + style: + type: table + options: + grouping: { } + row_class: '' + default_row_class: true + columns: + redirect_source__path: redirect_source__path + redirect_redirect__uri: redirect_redirect__uri + status_code: status_code + language: language + created: created + operations: operations + default: created + info: + redirect_source__path: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + redirect_redirect__uri: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + status_code: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + language: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + created: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + operations: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + override: true + sticky: false + summary: '' + empty_table: false + caption: '' + description: '' + row: + type: fields + query: + type: views_query + options: + query_comment: '' + disable_sql_rewrite: false + distinct: false + replica: false + query_tags: { } + relationships: { } + header: { } + footer: { } + display_extenders: { } + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } + cacheable: false + page_1: + id: page_1 + display_title: Page + display_plugin: page + position: 1 + display_options: + display_extenders: { } + path: admin/config/search/redirect + menu: + type: normal + title: Redirect + description: '' + weight: 0 + expanded: false + menu_name: admin + parent: hdbt_admin_tools.overview + context: '0' + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: { } + cacheable: false diff --git a/modules/helfi_base_content/config/optional/language/fi/views.view.redirect.yml b/modules/helfi_base_content/config/optional/language/fi/views.view.redirect.yml new file mode 100644 index 000000000..56a99a5b5 --- /dev/null +++ b/modules/helfi_base_content/config/optional/language/fi/views.view.redirect.yml @@ -0,0 +1,60 @@ +display: + default: + display_options: + filters: + status_code: + group_info: + group_items: + 7: + title: '300 Multiple Choices' + 1: { } + 2: { } + 3: { } + 4: { } + 5: { } + 6: { } + label: Tilakoodi + expose: + label: Tilakoodi + redirect_source__path: + expose: + label: Lähettäjä + redirect_redirect__uri: + expose: + label: Osoitteeseen + language: + expose: + label: 'Alkuperäinen kieli' + is_custom: + expose: + label: 'Käyttäjän luoma' + exposed_form: + options: + submit_button: Suodata + reset_button_label: Palauta + exposed_sorts_label: Lajittele + sort_asc_label: Nousevasti + sort_desc_label: Laskevasti + pager: + options: + tags: { } + expose: + items_per_page_label: 'Merkintöjä sivua kohti' + items_per_page_options_all_label: '- Kaikki -' + fields: + redirect_bulk_form: + action_title: Valinnalla + redirect_source__path: + label: Lähettäjä + created: + label: Luotu + is_custom: + label: 'Käyttäjän luoma' + empty: + area_text_custom: + content: 'Ei ole vielä uudelleenohjaksia.' + display_title: Oletus + page_1: + display_title: Sivu +label: Uudelleenohjaukset +description: Uudelleenohjaukset diff --git a/modules/helfi_base_content/helfi_base_content.install b/modules/helfi_base_content/helfi_base_content.install index e949f6767..4e1630fed 100644 --- a/modules/helfi_base_content/helfi_base_content.install +++ b/modules/helfi_base_content/helfi_base_content.install @@ -345,3 +345,11 @@ function helfi_base_content_update_9014(): void { \Drupal::service('helfi_platform_config.config_update_helper') ->update('helfi_base_content'); } + +/** + * UHF-9704: Configure view for redirect module. + */ +function helfi_base_content_update_9015(): void { + \Drupal::service('helfi_platform_config.config_update_helper') + ->update('helfi_base_content'); +} From c88838ede044417846c78ccddb02488089263088 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Thu, 5 Dec 2024 09:16:09 +0200 Subject: [PATCH 06/15] UHF-10539: Configure service --- helfi_platform_config.install | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/helfi_platform_config.install b/helfi_platform_config.install index 5fdac1aee..b70fe30db 100644 --- a/helfi_platform_config.install +++ b/helfi_platform_config.install @@ -7,6 +7,8 @@ declare(strict_types=1); +use Drupal\helfi_api_base\Environment\ActiveProjectRoles; +use Drupal\helfi_api_base\Environment\ProjectRoleEnum; use Drupal\helfi_platform_config\Entity\PublishableRedirect; use Drupal\user\Entity\User; @@ -267,3 +269,18 @@ function helfi_platform_config_update_9315() : void { // Update entity type again with the class change. $updateManager->updateEntityType($entityType); } + +/** + * UHF-10539: Update redirect entity type. + */ +function helfi_platform_config_update_9316() : void { + /** @var \Drupal\helfi_api_base\Environment\ActiveProjectRoles $projectRoles */ + $projectRoles = \Drupal::service(ActiveProjectRoles::class); + + if ($projectRoles->hasRole(ProjectRoleEnum::Core)) { + \Drupal::configFactory() + ->getEditable('helfi_platform_config.redirect_cleaner') + ->set('enable', TRUE) + ->save(); + } +} From ecedfbbb529d7788917ef34a37318d416ef6746f Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Thu, 5 Dec 2024 09:29:03 +0200 Subject: [PATCH 07/15] UHF-10539: Config fixes --- modules/helfi_base_content/helfi_base_content.install | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/helfi_base_content/helfi_base_content.install b/modules/helfi_base_content/helfi_base_content.install index 4e1630fed..87a7ce9e6 100644 --- a/modules/helfi_base_content/helfi_base_content.install +++ b/modules/helfi_base_content/helfi_base_content.install @@ -350,6 +350,7 @@ function helfi_base_content_update_9014(): void { * UHF-9704: Configure view for redirect module. */ function helfi_base_content_update_9015(): void { + \Drupal::service('config.factory')->getEditable('views.view.redirect')->delete(); \Drupal::service('helfi_platform_config.config_update_helper') ->update('helfi_base_content'); } From 93a22a2828bc036c2d2fc122b0edfd6af1afefd9 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Thu, 5 Dec 2024 09:31:14 +0200 Subject: [PATCH 08/15] UHF-10539: Sonarcloud changes --- src/Entity/PublishableRedirect.php | 2 +- src/PublishableRedirectRepository.php | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Entity/PublishableRedirect.php b/src/Entity/PublishableRedirect.php index e6808a63f..3c86282e1 100644 --- a/src/Entity/PublishableRedirect.php +++ b/src/Entity/PublishableRedirect.php @@ -37,7 +37,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type): a * FALSE if this redirect was created automatically by Drupal. */ public function isCustom(): bool { - return !!$this->getEntityKey('custom'); + return (bool)$this->getEntityKey('custom'); } } diff --git a/src/PublishableRedirectRepository.php b/src/PublishableRedirectRepository.php index aaf0fe670..8e902740d 100644 --- a/src/PublishableRedirectRepository.php +++ b/src/PublishableRedirectRepository.php @@ -24,10 +24,11 @@ public function findMatchingRedirect($source_path, array $query = [], $language $redirect = parent::findMatchingRedirect($source_path, $query, $language); // If the redirect is not published, return NULL instead. - if ($redirect instanceof EntityPublishedInterface) { - if (!$redirect->isPublished()) { - return NULL; - } + if ( + $redirect instanceof EntityPublishedInterface + && !$redirect->isPublished() + ) { + return NULL; } return $redirect; From 8308da5c873e213d7b8d156325c7be02cfa99395 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Mon, 9 Dec 2024 08:44:02 +0200 Subject: [PATCH 09/15] UHF-10539: Fix conflicts with redirect module config --- ...{views.view.redirect.yml => views.view.helfi_redirect.yml} | 4 ++-- ...{views.view.redirect.yml => views.view.helfi_redirect.yml} | 3 +++ .../helfi_base_content/config/rewrite/views.view.redirect.yml | 1 + modules/helfi_base_content/helfi_base_content.install | 1 - 4 files changed, 6 insertions(+), 3 deletions(-) rename modules/helfi_base_content/config/install/{views.view.redirect.yml => views.view.helfi_redirect.yml} (99%) rename modules/helfi_base_content/config/optional/language/fi/{views.view.redirect.yml => views.view.helfi_redirect.yml} (95%) create mode 100644 modules/helfi_base_content/config/rewrite/views.view.redirect.yml diff --git a/modules/helfi_base_content/config/install/views.view.redirect.yml b/modules/helfi_base_content/config/install/views.view.helfi_redirect.yml similarity index 99% rename from modules/helfi_base_content/config/install/views.view.redirect.yml rename to modules/helfi_base_content/config/install/views.view.helfi_redirect.yml index b9d4ed761..02c9962ea 100644 --- a/modules/helfi_base_content/config/install/views.view.redirect.yml +++ b/modules/helfi_base_content/config/install/views.view.helfi_redirect.yml @@ -1,4 +1,4 @@ -uuid: 30410398-1ba2-4548-aa8a-4c99cb8b82b4 +uuid: bf25e83d-5e50-4476-a09f-b072a996e778 langcode: en status: true dependencies: @@ -8,7 +8,7 @@ dependencies: - link - redirect - user -id: redirect +id: helfi_redirect label: Redirect module: views description: 'List of redirects' diff --git a/modules/helfi_base_content/config/optional/language/fi/views.view.redirect.yml b/modules/helfi_base_content/config/optional/language/fi/views.view.helfi_redirect.yml similarity index 95% rename from modules/helfi_base_content/config/optional/language/fi/views.view.redirect.yml rename to modules/helfi_base_content/config/optional/language/fi/views.view.helfi_redirect.yml index 56a99a5b5..df012b442 100644 --- a/modules/helfi_base_content/config/optional/language/fi/views.view.redirect.yml +++ b/modules/helfi_base_content/config/optional/language/fi/views.view.helfi_redirect.yml @@ -56,5 +56,8 @@ display: display_title: Oletus page_1: display_title: Sivu + display_options: + menu: + title: Uudelleenohjaukset label: Uudelleenohjaukset description: Uudelleenohjaukset diff --git a/modules/helfi_base_content/config/rewrite/views.view.redirect.yml b/modules/helfi_base_content/config/rewrite/views.view.redirect.yml new file mode 100644 index 000000000..416e5b4df --- /dev/null +++ b/modules/helfi_base_content/config/rewrite/views.view.redirect.yml @@ -0,0 +1 @@ +status: false diff --git a/modules/helfi_base_content/helfi_base_content.install b/modules/helfi_base_content/helfi_base_content.install index 87a7ce9e6..4e1630fed 100644 --- a/modules/helfi_base_content/helfi_base_content.install +++ b/modules/helfi_base_content/helfi_base_content.install @@ -350,7 +350,6 @@ function helfi_base_content_update_9014(): void { * UHF-9704: Configure view for redirect module. */ function helfi_base_content_update_9015(): void { - \Drupal::service('config.factory')->getEditable('views.view.redirect')->delete(); \Drupal::service('helfi_platform_config.config_update_helper') ->update('helfi_base_content'); } From d37771f0ac86c1adad135ff1156be117d3c04f0c Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Mon, 9 Dec 2024 08:44:08 +0200 Subject: [PATCH 10/15] UHF-10539: Fix default value --- helfi_platform_config.module | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/helfi_platform_config.module b/helfi_platform_config.module index db39b15c0..24a6fa564 100644 --- a/helfi_platform_config.module +++ b/helfi_platform_config.module @@ -10,6 +10,7 @@ declare(strict_types=1); use Drupal\Core\Access\AccessResult; use Drupal\Core\Breadcrumb\Breadcrumb; use Drupal\Core\Entity\ContentEntityInterface; +use Drupal\Core\Entity\EntityFormInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityPublishedInterface; use Drupal\Core\Field\BaseFieldDefinition; @@ -536,11 +537,16 @@ function helfi_platform_config_form_alter(&$form, FormStateInterface $form_state '#default_value' => [TRUE], ]; - $form['status'] = [ - '#type' => 'checkbox', - '#title' => new TranslatableMarkup('Published'), - '#default_value' => TRUE, - ]; + $formObject = $form_state->getFormObject(); + assert($formObject instanceof EntityFormInterface); + $redirect = $formObject->getEntity(); + if ($redirect instanceof EntityPublishedInterface) { + $form['status'] = [ + '#type' => 'checkbox', + '#title' => new TranslatableMarkup('Published'), + '#default_value' => $redirect->isPublished(), + ]; + }; } } From f67ed92becb550ec3058d509db2b483b9e64be4d Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Mon, 9 Dec 2024 08:57:49 +0200 Subject: [PATCH 11/15] UHF-10539: Fix phpcs --- src/Entity/PublishableRedirect.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entity/PublishableRedirect.php b/src/Entity/PublishableRedirect.php index 3c86282e1..86ff0fc9c 100644 --- a/src/Entity/PublishableRedirect.php +++ b/src/Entity/PublishableRedirect.php @@ -37,7 +37,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type): a * FALSE if this redirect was created automatically by Drupal. */ public function isCustom(): bool { - return (bool)$this->getEntityKey('custom'); + return (bool) $this->getEntityKey('custom'); } } From fd000b7ce2a32a864ab21dbeb8ff4f690fa0dff6 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Mon, 9 Dec 2024 09:07:58 +0200 Subject: [PATCH 12/15] UHF-10539: phpstan fixes --- helfi_platform_config.install | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/helfi_platform_config.install b/helfi_platform_config.install index e48e0f646..45fb3d45a 100644 --- a/helfi_platform_config.install +++ b/helfi_platform_config.install @@ -7,6 +7,7 @@ declare(strict_types=1); +use Drupal\Core\Field\BaseFieldDefinition; use Drupal\helfi_api_base\Environment\ActiveProjectRoles; use Drupal\helfi_api_base\Environment\ProjectRoleEnum; use Drupal\helfi_platform_config\Entity\PublishableRedirect; @@ -265,7 +266,9 @@ function helfi_platform_config_update_9316() : void { $field = $fields[$entityType->getKey($key)]; // Set published and custom initially to TRUE. - $field->setInitialValue(TRUE); + if ($field instanceof BaseFieldDefinition) { + $field->setInitialValue(TRUE); + } $updateManager->installFieldStorageDefinition( $entityType->getKey($key), From d54979e84c7bdaf27b7058bb7a1b119f1c46a52e Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Mon, 9 Dec 2024 09:27:43 +0200 Subject: [PATCH 13/15] UHF-10539: Remove config load away from service constructor --- src/RedirectCleaner.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/RedirectCleaner.php b/src/RedirectCleaner.php index 442380e5d..598cea35d 100644 --- a/src/RedirectCleaner.php +++ b/src/RedirectCleaner.php @@ -17,28 +17,24 @@ */ class RedirectCleaner { - /** - * Redirect cleaner configuration. - */ - private array $configuration; - /** * Constructs a new instance. */ public function __construct( - ConfigFactoryInterface $configFactory, + private readonly ConfigFactoryInterface $configFactory, private readonly EntityTypeManagerInterface $entityTypeManager, #[Autowire(service: 'logger.channel.helfi_platform_config')] private readonly LoggerInterface $logger, ) { - $this->configuration = $configFactory->get('helfi_platform_config.redirect_cleaner')->get(); } /** * Return TRUE if this feature is enabled. */ public function isEnabled(): bool { - return $this->configuration['enable'] ?? FALSE; + return $this->configFactory + ->get('helfi_platform_config.redirect_cleaner') + ->get('enable') ?? FALSE; } /** From 950b69499704183eb56d80223eec72beab7eff75 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Mon, 9 Dec 2024 10:03:01 +0200 Subject: [PATCH 14/15] UHF-10539: Convert function test to dtt test --- .../RedirectFormTest.php | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) rename tests/src/{Functional => ExistingSite}/RedirectFormTest.php (67%) diff --git a/tests/src/Functional/RedirectFormTest.php b/tests/src/ExistingSite/RedirectFormTest.php similarity index 67% rename from tests/src/Functional/RedirectFormTest.php rename to tests/src/ExistingSite/RedirectFormTest.php index 9bf99baf0..55aa13e28 100644 --- a/tests/src/Functional/RedirectFormTest.php +++ b/tests/src/ExistingSite/RedirectFormTest.php @@ -2,57 +2,36 @@ declare(strict_types=1); -namespace src\Functional; +namespace src\ExistingSite; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Url; use Drupal\helfi_platform_config\Entity\PublishableRedirect; -use Drupal\Tests\BrowserTestBase; -use Drupal\Tests\user\Traits\UserCreationTrait; +use Drupal\Tests\helfi_api_base\Functional\ExistingSiteTestBase; /** * Tests `redirect.add` form. + * + * @group helfi_platform_config */ -class RedirectFormTest extends BrowserTestBase { - - use UserCreationTrait; - - /** - * {@inheritdoc} - */ - protected $defaultTheme = 'stark'; +class RedirectFormTest extends ExistingSiteTestBase { /** - * {@inheritdoc} - */ - protected static $modules = [ - 'redirect', - 'helfi_platform_config', - ]; - - /** - * {@inheritDoc} + * Tests that saving redirect from entity form sets the custom field to TRUE. */ - protected function setUp() : void { - parent::setUp(); - + public function testRedirectForm() { $user = $this->createUser([ 'administer redirects', ]); $this->drupalLogin($user); - } - /** - * Tests that saving redirect from entity form sets the custom field to TRUE. - */ - public function testRedirectForm() { $edit = [ 'redirect_source[0][path]' => 'test', 'redirect_redirect[0][uri]' => '', 'status_code' => 307, ]; - $this->drupalGet(Url::fromRoute('redirect.add')->toString()); + $this->drupalGet(Url::fromRoute('redirect.add')); $this->submitForm($edit, 'Save'); $redirects = $this->container From ee72b4b040b067c604d231e11f9c86fa1d5a3128 Mon Sep 17 00:00:00 2001 From: Santeri Hurnanen Date: Mon, 9 Dec 2024 11:16:02 +0200 Subject: [PATCH 15/15] UHF-10539: Update documentation --- README.md | 1 + documentation/redirects.md | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 documentation/redirects.md diff --git a/README.md b/README.md index c63e5927f..b7d163767 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ This repository holds configuration for the Hel.fi platform. - [Update instructions (2.x to 3.x)](documentation/update.md) - [Two-factor authentication/TFA/MFA](/modules/helfi_tfa/README.md) - [JSON:API remote entities](/modules/helfi_etusivu_entities/README.md) +- [Redirects](/documentation/redirects.md) - [Users](/modules/helfi_users/README.md) ## Contact diff --git a/documentation/redirects.md b/documentation/redirects.md new file mode 100644 index 000000000..1d15173d5 --- /dev/null +++ b/documentation/redirects.md @@ -0,0 +1,21 @@ +# Publishable redirects + +This module alters [redirect entity type](../src/Entity/PublishableRedirect.php) from +[`redirect` module](https://www.drupal.org/project/redirect) +so that it implements EntityPublishedInterface and has +`is_custom` field. + +The redirect entities added or updated by any user from through the +entity from are automatically permanently marked as custom, while +redirects created automatically are not custom. + +If enabled, a cron job unpublished non-custom redirect entities that +are more than 6 months old. Enable the feature with: + +```php +\Drupal::configFactory() + ->getEditable('helfi_platform_config.redirect_cleaner') + ->set('enable', TRUE) + ->save(); +``` +