simple_account_policy-1.0.0/src/AccountPolicy.php

src/AccountPolicy.php
<?php

namespace Drupal\simple_account_policy;

use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\simple_account_policy\Event\AccountPolicyActivateEvent;
use Drupal\simple_account_policy\Event\AccountPolicyBlockEvent;
use Drupal\simple_account_policy\Event\AccountPolicyDeleteEvent;
use Drupal\simple_account_policy\Event\AccountPolicyWarningEvent;
use Drupal\user\UserInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
 * Account Policy.
 */
class AccountPolicy implements AccountPolicyInterface {

  use StringTranslationTrait;

  /**
   * Event Dispatcher.
   *
   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
   */
  protected $eventDispatcher;

  /**
   * Connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $db;

  /**
   * Config Factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $configFactory;

  /**
   * State Interface.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * Renderer Interface.
   *
   * @var \Drupal\Core\Render\RendererInterface
   */
  protected $renderer;

  /**
   * Policy validation parameters.
   *
   * @var \Drupal\Core\Config\Config
   */
  protected $config;

  /**
   * AccountPolicy constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   Config Factory.
   * @param \Drupal\Core\Database\Connection $database
   *   Connection.
   * @param \Drupal\Core\State\StateInterface $state
   *   State Interface.
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
   *   Event Dispatcher interface.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   Renderer Interface.
   */
  public function __construct(
    ConfigFactoryInterface $config_factory,
    Connection $database,
    StateInterface $state,
    EventDispatcherInterface $event_dispatcher,
    RendererInterface $renderer,
  ) {
    $this->configFactory = $config_factory;
    $this->db = $database;
    $this->state = $state;
    $this->eventDispatcher = $event_dispatcher;
    $this->renderer = $renderer;
    $this->config = $this->configFactory->getEditable('simple_account_policy.settings');
  }

  /**
   * {@inheritdoc}
   */
  public function applyPolicy(UserInterface $user): bool {
    $ignore_user = FALSE;

    $username_ignore_patterns = $this->config->get('username_ignore_patterns') ?? [];
    if (!empty($username_ignore_patterns)) {
      $pattern = '(' . implode('|', array_map('preg_quote', array_filter($username_ignore_patterns))) . ')';
      $ignore_user = (preg_match("/$pattern/", $user->getAccountName(), $matches));
    }

    // phpcs:disable Squiz.WhiteSpace.LanguageConstructSpacing.IncorrectSingle
    return
      // We need to validate an existing user.
      $user &&
      // Don't apply if user has bypass permission.
      !$user->hasPermission("bypass account policy") &&
      // Don't apply if user need to be ignored (by account name).
      !$ignore_user &&
      // Do not deleted user anonymous
      // https://www.drupal.org/project/simple_account_policy/issues/3388501.
      !$user->isAnonymous();
    // phpcs:enable
  }

  /**
   * {@inheritdoc}
   */
  public function validate(UserInterface $user, $data = []): array {
    $errors = [];

    if ($this->applyPolicy($user)) {

      // Get the values to validate. Use data first if provided.
      $mail = $data['mail'] ?? $user->getEmail();
      $username = $data['name'] ?? $user->getAccountName();

      // Check if username matches email.
      $username_match_email = $this->config->get('username_match_email') ?? FALSE;
      if ($username_match_email !== FALSE) {
        if ($mail !== $username) {
          $errors['name'][] = 'username_match_email';
        }
      }

      // Check if username matches patterns.
      $username_match_patterns = $this->config->get('username_match_patterns') ?? [];
      if (!empty($username_match_patterns)) {
        foreach ($username_match_patterns as $delta => $pattern) {
          if (!preg_match("/$pattern/", $mail, $matches)) {
            $errors['name'][] = 'username_match_pattern_' . $delta;
          }
        }
      }

      // Check if email matches patterns.
      $email_match_patterns = $this->config->get('email_match_patterns') ?? [];
      if (!empty($email_match_patterns)) {
        foreach ($email_match_patterns as $delta => $pattern) {
          if (!preg_match("/$pattern/", $mail, $matches)) {
            $errors['mail'][] = 'email_match_pattern_' . $delta;
          }
        }
      }
    }

    return $errors;
  }

  /**
   * {@inheritdoc}
   */
  public function policy(?UserInterface $user = NULL, array $errors = []): array {

    // Make sure we have the default field keys.
    $errors += [
      'mail' => [],
      'name' => [],
    ];

    $policy = [];

    if ($this->applyPolicy($user)) {

      // Check if username changes are allowed.
      $username_prevent_changes = $this->config->get('username_prevent_changes') ?? FALSE;
      if ($username_prevent_changes !== FALSE) {
        $policy['name'][] = [
          '#markup' => $user->isNew()
            ? (string) $this->t("The username can only be set once.")
            : (string) $this->t("The username cannot be changed."),
        ];
      }

      // Check if username matches email.
      $username_match_email = $this->config->get('username_match_email') ?? FALSE;
      if ($username_match_email !== FALSE) {
        $policy['name'][] = [
          '#wrapper_attributes' => ['class' => [in_array('username_match_email', $errors['name']) ? 'account-policy-invalid-rule marker' : 'account-policy-valid-rule']],
          '#markup' => (string) $this->t("The username must match the email address."),
        ];
      }

      // Check if username matches patterns.
      $username_match_patterns = array_filter($this->config->get('username_match_patterns') ?? []);
      if (!empty($username_match_patterns)) {
        foreach ($username_match_patterns as $delta => $pattern) {
          $policy['name'][] = [
            '#wrapper_attributes' => ['class' => [in_array('username_match_pattern_' . $delta, $errors['name']) ? 'account-policy-invalid-rule marker' : 'account-policy-valid-rule']],
            '#markup' => (string) $this->patternToMessage($pattern),
          ];
        }
      }

      // Check if email matches patterns.
      $email_match_patterns = array_filter($this->config->get('email_match_patterns') ?? []);
      if (!empty($email_match_patterns)) {
        foreach ($email_match_patterns as $delta => $pattern) {
          $policy['mail'][] = [
            '#wrapper_attributes' => ['class' => [in_array('email_match_pattern_' . $delta, $errors['name']) ? 'account-policy-invalid-rule marker' : 'account-policy-valid-rule']],
            '#markup' => (string) $this->patternToMessage($pattern),
          ];
        }
      }

      if (!empty($policy['name'])) {
        $elements = [
          'title' => [
            '#markup' => (string) $this->formatPlural(count($policy['name']),
              "The username must satisfy the following account policy rule:",
              "The username must satisfy the following account policy rules:"
            ),
          ],
          'rules' => [
            '#theme' => 'item_list',
            '#list_type' => 'ul',
            '#items' => $policy['name'],
          ],
        ];
        $policy['name'] = $this->renderer->renderPlain($elements);
      }

      if (!empty($policy['mail'])) {
        $elements = [
          'title' => [
            '#markup' => (string) $this->formatPlural(count($policy['mail']),
              "The email must satisfy the following account policy rule:",
              "The email must satisfy the following account policy rules:"
            ),
          ],
          'rules' => [
            '#theme' => 'item_list',
            '#list_type' => 'ul',
            '#items' => $policy['mail'],
          ],
        ];
        $policy['mail'] = $this->renderer->renderPlain($elements);
      }
    }
    else {
      $policy = [
        'mail' => $this->t("This user bypasses the account policy."),
        'name' => $this->t("This user bypasses the account policy."),
      ];
    }

    return $policy;
  }

  /**
   * {@inheritdoc}
   */
  public function getBlockTime(UserInterface $user): int {
    $block_time = 0;

    $inactive_period = (string) $this->config->get('inactive_period') ?? '';

    if (!empty($inactive_period)) {

      $lastAccessedTime = $user->getLastAccessedTime();
      if ($lastAccessedTime === '0') {
        $lastAccessedTime = $user->getCreatedTime();
      }

      if (ctype_digit($inactive_period)) {
        $block_time = $lastAccessedTime + intval($inactive_period);
      }
      else {
        $block_time = time() + ($lastAccessedTime - strtotime('-' . $inactive_period));
      }
    }

    return $block_time;
  }

  /**
   * {@inheritdoc}
   */
  public function getWarningTime(UserInterface $user): int {
    $warning_time = 0;

    $block_time = $this->getBlockTime($user);
    if ($block_time) {

      $inactive_warning = (string) $this->config->get('inactive_warning') ?? '';
      if (!empty($inactive_warning)) {

        if (ctype_digit($inactive_warning)) {
          $warning_time = $block_time - intval($inactive_warning);
        }
        else {
          $warning_time = time() + ($block_time - strtotime('+' . $inactive_warning));
        }

      }
    }

    return $warning_time;
  }

  /**
   * {@inheritdoc}
   */
  public function inactiveInterval(): int {
    return $this->config->get('inactive_interval') ?? 86400;
  }

  /**
   * {@inheritdoc}
   */
  public function getDeleteAfterTime(): int {

    $delete_after_time = (string) $this->config->get('delete_after_time') ?? 0;

    if (!empty($delete_after_time)) {

      if (ctype_digit($delete_after_time)) {
        $delete_after_time = time() - intval($delete_after_time);
      }
      else {
        $delete_after_time = strtotime("$delete_after_time ago") ?: 0;
      }

    }

    return $delete_after_time;
  }

  /**
   * {@inheritdoc}
   */
  public function shouldIssueWarning(UserInterface $user): bool {
    $warning_time = $this->getWarningTime($user);
    return ($warning_time && !$this->warningIssued($user) && time() > $warning_time);
  }

  /**
   * {@inheritdoc}
   */
  public function warningIssued(UserInterface $user): bool {
    $warned_users = $this->state->get('simple_account_policy.warned_users', []);
    return array_key_exists($user->id(), $warned_users);
  }

  /**
   * {@inheritdoc}
   */
  public function issueWarning(UserInterface $user): void {
    // Keep track of issued warnings.
    $warned_users = $this->state->get('simple_account_policy.warned_users', []);
    $warned_users[$user->id()] = $user->id();
    $this->state->set('simple_account_policy.warned_users', $warned_users);

    // Send out an event so others can react to this as well.
    $event = new AccountPolicyWarningEvent($user, $this);
    $this->eventDispatcher->dispatch($event, AccountPolicyWarningEvent::EVENT_NAME);
  }

  /**
   * {@inheritdoc}
   */
  public function isInactive(UserInterface $user): bool {

    $block_time = $this->getBlockTime($user);

    return ($block_time && $user->isActive() && time() > $block_time);
  }

  /**
   * {@inheritdoc}
   */
  public function block(UserInterface $user): void {
    $event = new AccountPolicyBlockEvent($user, $this);
    $this->eventDispatcher->dispatch($event, AccountPolicyBlockEvent::EVENT_NAME);
  }

  /**
   * {@inheritdoc}
   */
  public function activate(UserInterface $user): void {
    // Keep track of issued warnings.
    $warned_users = $this->state->get('simple_account_policy.warned_users', []);
    unset($warned_users[$user->id()]);
    $this->state->set('simple_account_policy.warned_users', $warned_users);

    // Send out an event so others can react to this as well.
    $event = new AccountPolicyActivateEvent($user, $this);
    $this->eventDispatcher->dispatch($event, AccountPolicyActivateEvent::EVENT_NAME);
  }

  /**
   * Pretty print a regular expression pattern.
   *
   * @param array $pattern
   *   Pattern.
   *
   * @return \Drupal\Core\StringTranslation\TranslatableMarkup
   *   Return Statement.
   */
  protected function patternToMessage(string $pattern): string {

    $beginsWithApostrophe = ($pattern[0] == '^');
    $endsWithDollar = ($pattern[strlen($pattern) - 1] == '$');

    if ($beginsWithApostrophe && $endsWithDollar) {
      $message = $this->t("Must match %pattern.", ['%pattern' => trim($pattern, "^$")]);
    }
    else {
      if ($beginsWithApostrophe) {
        $message = $this->t("Must begin with %pattern.", ['%pattern' => ltrim($pattern, "^")]);
      }
      elseif ($endsWithDollar) {
        $message = $this->t("Must end with %pattern.", ['%pattern' => rtrim($pattern, "$")]);
      }
      else {
        $message = $this->t("Must contain %pattern.", ['%pattern' => $pattern]);
      }
    }

    return $message;
  }

  /**
   * {@inheritdoc}
   */
  public function shouldBeDeleted(UserInterface $user): bool {
    $lastLoginTime = $user->getLastAccessedTime() ?: $user->getCreatedTime();
    $deleteAfterTime = $this->getDeleteAfterTime();
    if (empty($deleteAfterTime)) {
      return FALSE;
    }

    if ($lastLoginTime < $deleteAfterTime) {
      return TRUE;
    }

    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function delete(UserInterface $user): void {
    $cancelMethod = $this->config->get('user_cancel_method');

    if (empty($cancelMethod)) {
      $cancelMethod = 'user_cancel_reassign';
    }

    $event = new AccountPolicyDeleteEvent($user, $this, $cancelMethod);
    $this->eventDispatcher->dispatch($event, AccountPolicyDeleteEvent::EVENT_NAME);
  }

  /**
   * Get the policy configuration.
   *
   * @return \Drupal\Core\Config\Config
   *   The policy configuration object.
   */
  public function getConfiguration(): Config {
    return $this->config;
  }

}

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

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