Verified Commit badd417e authored by Lauri Timmanee's avatar Lauri Timmanee
Browse files

Issue #2245767 by John Pitcairn, andrewmacpherson, danflanagan8, leymannx,...

Issue #2245767 by John Pitcairn, andrewmacpherson, danflanagan8, leymannx, tim.plunkett, mpolishchuck, tobiasb, olli, dawehner, Anas_maw, SpadXIII, _utsavsharma, benjifisher, ankithashetty, jidrone, SimeonKesmev, Daniel Korte, ameymudras, jyotimishra-developer, alexpott, smustgrave, geek-merlin, catch, DuaelFr, Gábor Hojtsy, lauriii, ckrina, quietone: Allow blocks to be configured to show/hide on 200/403/404 response pages
parent 4bfd55f3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@
      }

      $(
        '[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-entity-bundlenode"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"]',
        '[data-drupal-selector="edit-visibility-node-type"], [data-drupal-selector="edit-visibility-entity-bundlenode"], [data-drupal-selector="edit-visibility-language"], [data-drupal-selector="edit-visibility-user-role"], [data-drupal-selector="edit-visibility-response-status"]',
      ).drupalSetSummary(checkboxesSummary);

      $(
+13 −10
Original line number Diff line number Diff line
@@ -247,16 +247,23 @@ protected function buildVisibilityInterface(array $form, FormStateInterface $for
      $form[$condition_id] = $condition_form;
    }

    if (isset($form['entity_bundle:node'])) {
      $form['entity_bundle:node']['negate']['#type'] = 'value';
      $form['entity_bundle:node']['negate']['#title_display'] = 'invisible';
      $form['entity_bundle:node']['negate']['#value'] = $form['entity_bundle:node']['negate']['#default_value'];
    // Disable negation for specific conditions.
    $disable_negation = [
      'entity_bundle:node',
      'language',
      'response_status',
      'user_role',
    ];
    foreach ($disable_negation as $condition) {
      if (isset($form[$condition])) {
        $form[$condition]['negate']['#type'] = 'value';
        $form[$condition]['negate']['#value'] = $form[$condition]['negate']['#default_value'];
      }
    }

    if (isset($form['user_role'])) {
      $form['user_role']['#title'] = $this->t('Roles');
      unset($form['user_role']['roles']['#description']);
      $form['user_role']['negate']['#type'] = 'value';
      $form['user_role']['negate']['#value'] = $form['user_role']['negate']['#default_value'];
    }
    if (isset($form['request_path'])) {
      $form['request_path']['#title'] = $this->t('Pages');
@@ -268,10 +275,6 @@ protected function buildVisibilityInterface(array $form, FormStateInterface $for
        $this->t('Hide for the listed pages'),
      ];
    }
    if (isset($form['language'])) {
      $form['language']['negate']['#type'] = 'value';
      $form['language']['negate']['#value'] = $form['language']['negate']['#default_value'];
    }
    return $form;
  }

+16 −4
Original line number Diff line number Diff line
@@ -35,11 +35,13 @@ public function testBlockVisibility() {
      'settings[label]' => $title,
      'settings[label_display]' => TRUE,
    ];
    // Set the block to be hidden on any user path, and to be shown only to
    // authenticated users.
    // Set the block to be hidden on any user path, to be shown only to
    // authenticated users, and to be shown only on 200 and 404 responses.
    $edit['visibility[request_path][pages]'] = '/user*';
    $edit['visibility[request_path][negate]'] = TRUE;
    $edit['visibility[user_role][roles][' . RoleInterface::AUTHENTICATED_ID . ']'] = TRUE;
    $edit['visibility[response_status][status_codes][200]'] = 200;
    $edit['visibility[response_status][status_codes][404]'] = 404;
    $this->drupalGet('admin/structure/block/add/' . $block_name . '/' . $default_theme);
    $this->assertSession()->checkboxChecked('edit-visibility-request-path-negate-0');

@@ -48,16 +50,26 @@ public function testBlockVisibility() {

    $this->clickLink('Configure');
    $this->assertSession()->checkboxChecked('edit-visibility-request-path-negate-1');
    $this->assertSession()->checkboxChecked('edit-visibility-response-status-status-codes-200');
    $this->assertSession()->checkboxChecked('edit-visibility-response-status-status-codes-404');

    // Confirm that the block is displayed on the front page.
    // Confirm that the block is displayed on the front page (200 response).
    $this->drupalGet('');
    $this->assertSession()->pageTextContains($title);

    // Confirm that the block is not displayed according to block visibility
    // Confirm that the block is not displayed according to path visibility
    // rules.
    $this->drupalGet('user');
    $this->assertSession()->pageTextNotContains($title);

    // Confirm that the block is displayed on a 404 response.
    $this->drupalGet('/0/null');
    $this->assertSession()->pageTextContains($title);

    // Confirm that the block is not displayed on a 403 response.
    $this->drupalGet('/admin/config/system/cron');
    $this->assertSession()->pageTextNotContains($title);

    // Confirm that the block is not displayed to anonymous users.
    $this->drupalLogout();
    $this->drupalGet('');
+8 −0
Original line number Diff line number Diff line
@@ -357,6 +357,14 @@ condition.plugin.request_path:
    pages:
      type: string

condition.plugin.response_status:
  type: condition.plugin
  mapping:
    status_codes:
      type: sequence
      sequence:
        type: integer

system.feature_flags:
  type: config_object
  label: 'System Feature Flags'
+124 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\system\Plugin\Condition;

use Drupal\Core\Condition\ConditionPluginBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;

/**
 * Provides a 'Response status' condition.
 *
 * @Condition(
 *   id = "response_status",
 *   label = @Translation("Response status"),
 * )
 */
class ResponseStatus extends ConditionPluginBase implements ContainerFactoryPluginInterface {

  /**
   * The request stack.
   */
  protected RequestStack $requestStack;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
    $instance = new static($configuration, $plugin_id, $plugin_definition);
    $instance->setRequestStack($container->get('request_stack'));
    return $instance;
  }

  public function setRequestStack(RequestStack $requestStack): void {
    $this->requestStack = $requestStack;
  }

  /**
   * {@inheritdoc}
   */
  public function isNegated(): bool {
    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration(): array {
    return ['status_codes' => []] + parent::defaultConfiguration();
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
    $status_codes = [
      Response::HTTP_OK => $this->t('Success (@status_code)', ['@status_code' => Response::HTTP_OK]),
      Response::HTTP_FORBIDDEN => $this->t('Access denied (@status_code)', ['@status_code' => Response::HTTP_FORBIDDEN]),
      Response::HTTP_NOT_FOUND => $this->t('Page not found (@status_code)', ['@status_code' => Response::HTTP_NOT_FOUND]),
    ];
    $form['status_codes'] = [
      '#type' => 'checkboxes',
      '#title' => $this->t('Response status'),
      '#options' => $status_codes,
      '#default_value' => $this->configuration['status_codes'],
      '#description' => $this->t('Shows the block on pages with any matching response status. If nothing is checked, the block is shown on all pages. Other response statuses are not used.'),
    ];
    return parent::buildConfigurationForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void {
    $this->configuration['status_codes'] = array_keys(array_filter($form_state->getValue('status_codes')));
    parent::submitConfigurationForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function summary(): PluralTranslatableMarkup {
    $allowed_codes = $this->configuration['status_codes'];
    $status_codes = [Response::HTTP_OK, Response::HTTP_FORBIDDEN, Response::HTTP_NOT_FOUND];
    $result = empty($allowed_codes) ? $status_codes : $allowed_codes;
    $count = count($result);
    $codes = implode(', ', $result);
    if (!empty($this->configuration['negate'])) {
      return $this->formatPlural($count, 'Request response code is not: @codes', 'Request response code is not one of the following: @codes', ['@codes' => $codes]);
    }
    return $this->formatPlural($count, 'Request response code is: @codes', 'Request response code is one of the following: @codes', ['@codes' => $codes]);
  }

  /**
   * {@inheritdoc}
   */
  public function evaluate(): bool {
    $allowed_codes = $this->configuration['status_codes'];
    if (empty($allowed_codes)) {
      return TRUE;
    }
    $exception = $this->requestStack->getCurrentRequest()->attributes->get('exception');
    if ($exception) {
      return ($exception instanceof HttpExceptionInterface && in_array($exception->getStatusCode(), $allowed_codes, TRUE));
    }
    return in_array(Response::HTTP_OK, $allowed_codes, TRUE);
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts(): array {
    $contexts = parent::getCacheContexts();
    $contexts[] = 'url.path';
    return $contexts;
  }

}
Loading