From afdee270cb12cb1b290668222279fbd8cbbe2d06 Mon Sep 17 00:00:00 2001 From: Dave Long <dave@longwaveconsulting.com> Date: Mon, 22 Jul 2024 18:16:33 +0100 Subject: [PATCH] Issue #2502637 by bnjmnm, shumer, smustgrave, cilefen, Wim Leers, legolasbo, quietone, Xano, nikitagupta, DanielVeza, vegantriathlete, gaurav-mathur, priyanka.sahni, alexpott, dww, rkoller, dqd, swentel, eltermann, Alan D., ZenDoodles, David_Rothstein, sun, welly, pameeela: Disabled text formats can't be seen in the GUI --- core/modules/filter/filter.routing.yml | 8 ++ .../filter/src/Element/ProcessedText.php | 5 ++ .../filter/src/Entity/FilterFormat.php | 7 +- .../src/FilterFormatAccessControlHandler.php | 2 +- .../filter/src/FilterFormatListBuilder.php | 29 ++++--- .../filter/src/Form/FilterDisableForm.php | 5 +- .../filter/src/Form/FilterEnableForm.php | 54 ++++++++++++ .../tests/src/Functional/FilterAdminTest.php | 84 +++++++++++++++++++ 8 files changed, 179 insertions(+), 15 deletions(-) create mode 100644 core/modules/filter/src/Form/FilterEnableForm.php diff --git a/core/modules/filter/filter.routing.yml b/core/modules/filter/filter.routing.yml index 5b56da7089f0..799722cc0dcd 100644 --- a/core/modules/filter/filter.routing.yml +++ b/core/modules/filter/filter.routing.yml @@ -45,3 +45,11 @@ entity.filter_format.disable: _title: 'Disable text format' requirements: _entity_access: 'filter_format.disable' + +entity.filter_format.enable: + path: '/admin/config/content/formats/manage/{filter_format}/enable' + defaults: + _entity_form: 'filter_format.enable' + _title: 'Enable text format' + requirements: + _entity_access: 'filter_format.enable' diff --git a/core/modules/filter/src/Element/ProcessedText.php b/core/modules/filter/src/Element/ProcessedText.php index 7ec8f662458f..a9505799b687 100644 --- a/core/modules/filter/src/Element/ProcessedText.php +++ b/core/modules/filter/src/Element/ProcessedText.php @@ -85,6 +85,11 @@ public static function preRenderText($element) { $message = !$format ? 'Missing text format: %format.' : 'Disabled text format: %format.'; static::logger('filter')->alert($message, ['%format' => $format_id]); $element['#markup'] = ''; + // Associate the disabled text format's cache tag, to ensure re-enabling + // the text format invalidates the appropriate render cache items. + if ($format !== NULL) { + $element['#cache']['tags'] = Cache::mergeTags($element['#cache']['tags'] ?? [], $format->getCacheTags()); + } return $element; } diff --git a/core/modules/filter/src/Entity/FilterFormat.php b/core/modules/filter/src/Entity/FilterFormat.php index 699b6a99d4a4..dab96a0e9e12 100644 --- a/core/modules/filter/src/Entity/FilterFormat.php +++ b/core/modules/filter/src/Entity/FilterFormat.php @@ -3,6 +3,7 @@ namespace Drupal\filter\Entity; use Drupal\Component\Plugin\PluginInspectionInterface; + use Drupal\Core\Config\Action\Attribute\ActionMethod; use Drupal\Core\Config\Entity\ConfigEntityBase; use Drupal\Core\Entity\EntityWithPluginCollectionInterface; @@ -30,7 +31,8 @@ * "form" = { * "add" = "Drupal\filter\FilterFormatAddForm", * "edit" = "Drupal\filter\FilterFormatEditForm", - * "disable" = "Drupal\filter\Form\FilterDisableForm" + * "disable" = "Drupal\filter\Form\FilterDisableForm", + * "enable" = "Drupal\filter\Form\FilterEnableForm", * }, * "list_builder" = "Drupal\filter\FilterFormatListBuilder", * "access" = "Drupal\filter\FilterFormatAccessControlHandler", @@ -45,7 +47,8 @@ * }, * links = { * "edit-form" = "/admin/config/content/formats/manage/{filter_format}", - * "disable" = "/admin/config/content/formats/manage/{filter_format}/disable" + * "disable" = "/admin/config/content/formats/manage/{filter_format}/disable", + * "enable" = "/admin/config/content/formats/manage/{filter_format}/enable", * }, * config_export = { * "name", diff --git a/core/modules/filter/src/FilterFormatAccessControlHandler.php b/core/modules/filter/src/FilterFormatAccessControlHandler.php index 2dcb6dc7d1ef..faaed4f5c516 100644 --- a/core/modules/filter/src/FilterFormatAccessControlHandler.php +++ b/core/modules/filter/src/FilterFormatAccessControlHandler.php @@ -41,7 +41,7 @@ protected function checkAccess(EntityInterface $filter_format, $operation, Accou return AccessResult::forbidden(); } - if (in_array($operation, ['disable', 'update', 'view'])) { + if (in_array($operation, ['disable', 'update', 'view', 'enable'])) { return parent::checkAccess($filter_format, $operation, $account); } diff --git a/core/modules/filter/src/FilterFormatListBuilder.php b/core/modules/filter/src/FilterFormatListBuilder.php index d63ea6c9fc47..1aacdd87404d 100644 --- a/core/modules/filter/src/FilterFormatListBuilder.php +++ b/core/modules/filter/src/FilterFormatListBuilder.php @@ -75,22 +75,13 @@ public function getFormId() { return 'filter_admin_overview'; } - /** - * {@inheritdoc} - */ - public function load() { - // Only list enabled filters. - return array_filter(parent::load(), function ($entity) { - return $entity->status(); - }); - } - /** * {@inheritdoc} */ public function buildHeader() { $header['label'] = $this->t('Name'); $header['roles'] = $this->t('Roles'); + $header['status'] = $this->t('Status'); return $header + parent::buildHeader(); } @@ -124,7 +115,13 @@ public function buildRow(EntityInterface $entity) { '#context' => ['list_style' => 'comma-list'], ]; } - + if ($entity->status()) { + $status = $this->t('Enabled'); + } + else { + $status = $this->t('Disabled'); + } + $row['status']['#markup'] = $status; return $row + parent::buildRow($entity); } @@ -143,6 +140,16 @@ public function getDefaultOperations(EntityInterface $entity) { unset($operations['disable']); } + // Remove disable and edit operations for disabled formats. + if (!$entity->status()) { + if (isset($operations['disable'])) { + unset($operations['disable']); + } + if (isset($operations['edit'])) { + unset($operations['edit']); + } + } + return $operations; } diff --git a/core/modules/filter/src/Form/FilterDisableForm.php b/core/modules/filter/src/Form/FilterDisableForm.php index 0c213a26666e..594f06057113 100644 --- a/core/modules/filter/src/Form/FilterDisableForm.php +++ b/core/modules/filter/src/Form/FilterDisableForm.php @@ -38,7 +38,10 @@ public function getConfirmText() { * {@inheritdoc} */ public function getDescription() { - return $this->t('Disabled text formats are completely removed from the administrative interface, and any content stored with that format will not be displayed. This action cannot be undone.'); + return $this->t( + 'Any content saved with the %format text format will not be displayed on the site until it is resaved with an enabled text format.', + ['%format' => $this->entity->label()], + ); } /** diff --git a/core/modules/filter/src/Form/FilterEnableForm.php b/core/modules/filter/src/Form/FilterEnableForm.php new file mode 100644 index 000000000000..2dbe7f9c2c9c --- /dev/null +++ b/core/modules/filter/src/Form/FilterEnableForm.php @@ -0,0 +1,54 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\filter\Form; + +use Drupal\Core\Entity\EntityConfirmFormBase; +use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; +use Drupal\Core\Url; + +/** + * Provides the filter format enable form. + */ +class FilterEnableForm extends EntityConfirmFormBase { + + /** + * {@inheritdoc} + */ + public function getQuestion(): TranslatableMarkup { + return $this->t('Are you sure you want to enable the text format %format?', ['%format' => $this->entity->label()]); + } + + /** + * {@inheritdoc} + */ + public function getCancelUrl(): Url { + return new Url('filter.admin_overview'); + } + + /** + * {@inheritdoc} + */ + public function getConfirmText(): TranslatableMarkup { + return $this->t('Enable'); + } + + /** + * {@inheritdoc} + */ + public function getDescription(): TranslatableMarkup { + return $this->t('This will make the %format format available.', ['%format' => $this->entity->label()]); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state): void { + $this->entity->enable()->save(); + $this->messenger()->addMessage($this->t('Enabled text format %format.', ['%format' => $this->entity->label()])); + $form_state->setRedirectUrl($this->getCancelUrl()); + } + +} diff --git a/core/modules/filter/tests/src/Functional/FilterAdminTest.php b/core/modules/filter/tests/src/Functional/FilterAdminTest.php index e35db530f0c3..2b501f1d921f 100644 --- a/core/modules/filter/tests/src/Functional/FilterAdminTest.php +++ b/core/modules/filter/tests/src/Functional/FilterAdminTest.php @@ -478,4 +478,88 @@ public function testDisabledFormat(): void { $this->assertSession()->pageTextContains(sprintf('Missing text format: %s.', $format_id)); } + /** + * Tests enabling and disabling of filters. + */ + public function testFilterEnableAndDisable(): void { + $filter_test = FilterFormat::create([ + 'format' => 'filter_test', + 'name' => 'Filter test', + 'filters' => [ + 'filter_html' => [ + 'status' => TRUE, + 'weight' => -10, + 'settings' => [ + 'allowed_html' => '<p> <br> <strong> <a> <em> <h4>', + ], + ], + ], + ]); + $filter_test->save(); + + // Create a node type and add a standard body field. + $node_type = NodeType::create([ + 'type' => $this->randomMachineName(), + 'name' => $this->randomString(), + ]); + $node_type->save(); + node_add_body_field($node_type, $this->randomString()); + + // Create a new node of the new node type. + $title = $this->randomString(); + $node = Node::create([ + 'type' => $node_type->id(), + 'title' => $title, + ]); + $body_value = 'I belong to a filter that might be shut off!'; + $node->body->value = $body_value; + $node->body->format = 'filter_test'; + $node->save(); + + // Confirm the body field using the filter test is visible. + $this->drupalGet($node->toUrl()); + $this->assertSession()->pageTextContains($title); + $this->assertSession()->pageTextContains($body_value); + + $this->drupalGet('admin/config/content/formats'); + + // Verify filter_test links. + $this->assertSession()->linkByHrefExists('/admin/config/content/formats/manage/filter_test/disable'); + $this->assertSession()->linkByHrefNotExists('/admin/config/content/formats/manage/filter_test/enable'); + + // Test the configure link appears for Filter test. + $this->assertSession()->elementExists('xpath', '//a[contains(@href, "/admin/config/content/formats/manage/filter_test") and text()="Configure"]'); + + // Disable 'Filter test'. + $this->getSession()->getPage()->find('css', '[href*="/admin/config/content/formats/manage/filter_test/disable"]')->click(); + $this->assertSession()->pageTextContains('Are you sure you want to disable the text format Filter test?'); + $this->getSession()->getPage()->find('css', '#edit-submit')->click(); + + // Verify filter_test links after filter_test is disabled. + $this->assertSession()->linkByHrefExists('/admin/config/content/formats/manage/filter_test/enable'); + $this->assertSession()->linkByHrefNotExists('/admin/config/content/formats/manage/filter_test/disable'); + + // Test the configure link doesn't appear for Filter test. + $this->assertSession()->elementNotExists('xpath', '//a[contains(@href, "/admin/config/content/formats/manage/filter_test") and text()="Configure"]'); + + // Confirm the field using the now-disabled filter is not visible. + $this->drupalGet($node->toUrl()); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->pageTextContains($title); + $this->assertSession()->pageTextNotContains($body_value); + + // Re-enable the filter that we disabled. + $this->drupalGet('admin/config/content/formats'); + $this->getSession()->getPage()->find('css', '[href*="/admin/config/content/formats/manage/filter_test/enable"]')->click(); + $this->assertSession()->pageTextContains('Are you sure you want to enable the text format Filter test?'); + $this->getSession()->getPage()->find('css', '#edit-submit')->click(); + + // Confirm the presence of enable/disable operations has updated properly. + $this->assertSession()->linkByHrefExists('/admin/config/content/formats/manage/filter_test/disable'); + $this->assertSession()->linkByHrefNotExists('/admin/config/content/formats/manage/filter_test/enable'); + + $this->drupalGet($node->toUrl()); + $this->assertSession()->pageTextContains($body_value); + } + } -- GitLab