entity_legal-4.0.x-dev/src/Plugin/EntityLegal/Redirect.php

src/Plugin/EntityLegal/Redirect.php
<?php

declare(strict_types=1);

namespace Drupal\entity_legal\Plugin\EntityLegal;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Messenger\MessengerTrait;
use Drupal\Core\Routing\RedirectDestinationTrait;
use Drupal\Core\Routing\ResettableStackedRouteMatchInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\entity_legal\EntityLegalDocumentInterface;
use Drupal\entity_legal\EntityLegalPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;

/**
 * Method class for redirecting existing users to accept a legal document.
 *
 * @EntityLegal(
 *   id = "redirect",
 *   label = @Translation("Redirect every page load to legal document until accepted"),
 *   type = "existing_users",
 * )
 */
class Redirect extends EntityLegalPluginBase {

  use MessengerTrait;
  use RedirectDestinationTrait;
  use StringTranslationTrait;

  /**
   * Constructs a new plugin instance.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager service.
   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
   *   The current user.
   * @param \Drupal\Core\Routing\ResettableStackedRouteMatchInterface $routeMatch
   *   The current route match service.
   * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $privateTempStoreFactory
   *   The private temp store factory service.
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    protected EntityTypeManagerInterface $entityTypeManager,
    protected AccountProxyInterface $currentUser,
    protected ResettableStackedRouteMatchInterface $routeMatch,
    protected PrivateTempStoreFactory $privateTempStoreFactory,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $this->entityTypeManager, $this->currentUser);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('entity_type.manager'),
      $container->get('current_user'),
      $container->get('current_route_match'),
      $container->get('tempstore.private')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function execute(array &$context = []): void {
    foreach ($this->getDocumentsForMethod() as $document) {
      /** @var \Symfony\Component\HttpKernel\Event\ResponseEvent $event */
      $event = $context['event'];
      $request = $event->getRequest();

      // The acceptance of a legal document is applicable only to humans.
      if ($request->getRequestFormat() !== 'html') {
        return;
      }

      // Don't redirect on POST requests.
      if (!$request->isMethodSafe()) {
        return;
      }

      if (!$routeName = $this->routeMatch->getRouteName()) {
        // Unrouted?
        return;
      }

      if ($this->isExcludedRoute($routeName, $document)) {
        return;
      }

      // Do not redirect password reset.
      if ($this->isPasswordReset($event->getRequest())) {
        return;
      }

      if ($messages = $this->messenger()->all()) {
        // Save any messages set for the destination page.
        // @see \Drupal\entity_legal\Form\EntityLegalDocumentAcceptanceForm::submitForm()
        $this->privateTempStoreFactory->get('entity_legal')->set('postponed_messages', $messages);
        $this->messenger()->deleteAll();
      }

      $this->messenger()->addWarning($this->t('You must accept this agreement before continuing.'));

      $entityUrl = $document->toUrl()
        ->setOption('query', $this->getDestinationArray())
        ->setAbsolute(TRUE)
        ->toString();
      $event->setResponse(new TrustedRedirectResponse($entityUrl));

      // Remove destination cause the RedirectResponseSubscriber redirects, and
      // in some cases, it brings redirect loops.
      $request->query->remove('destination');
      $request->request->remove('destination');
    }
  }

  /**
   * Checks if the current route is excluded.
   *
   * @param string $routeName
   *   The route name.
   * @param \Drupal\entity_legal\EntityLegalDocumentInterface $document
   *   The legal document entity.
   *
   * @return bool
   *   If the current route is excluded.
   */
  protected function isExcludedRoute(string $routeName, EntityLegalDocumentInterface $document): bool {
    $excludedRoutes = [
      'system.csrftoken',
      'user.logout',
      'user.logout.confirm',
      'system.js_asset',
      'system.css_asset',
      $document->toUrl()->getRouteName(),
    ];
    return in_array($routeName, $excludedRoutes);
  }

  /**
   * Check if this is a valid password reset request.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The HTTP request object.
   *
   * @return bool
   *   If this is a valid password reset request.
   */
  protected function isPasswordReset(Request $request): bool {
    // Unblock only the current user account edit form.
    if ($this->routeMatch->getRouteName() !== 'entity.user.edit_form' && $this->routeMatch->getRawParameter('user') != $this->currentUser->id()) {
      return FALSE;
    }

    // The password reset token should be present.
    if (!$passResetToken = $request->get('pass-reset-token')) {
      return FALSE;
    }

    // Now we check if it's a valid token.
    // @see \Drupal\user\Controller\UserController::resetPassLogin()
    // @see \Drupal\user\AccountForm::form()
    $sessionKey = "pass_reset_{$this->currentUser->id()}";
    if (!isset($_SESSION[$sessionKey]) || !hash_equals($_SESSION[$sessionKey], $passResetToken)) {
      return FALSE;
    }

    return TRUE;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc