decoupled_json_log-1.0.x-dev/src/Plugin/Validation/Constraint/RateLimitPerUserValidator.php

src/Plugin/Validation/Constraint/RateLimitPerUserValidator.php
<?php

declare(strict_types=1);

namespace Drupal\decoupled_json_log\Plugin\Validation\Constraint;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\decoupled_json_log\Exception\DecoupledJsonLogException;
use Drupal\decoupled_json_log\LogJsonInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Webmozart\Assert\Assert;

/**
 * Validates the RateLimitPerUser constraint.
 */
final class RateLimitPerUserValidator extends ConstraintValidator implements ContainerInjectionInterface {

  public function __construct(
    protected AccountInterface $currentUser,
    protected EntityTypeManagerInterface $entityTypeManager,
    protected TimeInterface $time,
    protected ConfigFactoryInterface $configFactory,
  ) {
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public static function create(ContainerInterface $container): static {
    return new self(
      $container->get('current_user'),
      $container->get('entity_type.manager'),
      $container->get('datetime.time'),
      $container->get('config.factory'),
    );
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function validate(mixed $value, Constraint $constraint): void {
    if (is_object($value)) {
      if (method_exists($value, 'label')) {
        $name = $value->label();
      }
      else {
        throw new DecoupledJsonLogException('Value does not have label() method!');
      }
      if ($value instanceof LogJsonInterface && is_string($name) && !$this->isPostCountBelowLimit()) {
        if ($constraint instanceof RateLimitPerUser) {
          $this->context->addViolation($constraint->postIntervalExceeded, ['%value' => $value->label()]);
        }
        else {
          throw new DecoupledJsonLogException('Failed to set constraint RateLimitPerUser!');
        }
      }
    }
    else {
      throw new DecoupledJsonLogException('Value must be an object!');
    }
  }

  /**
   * Checks whether the current user's log post count is below the limit.
   *
   * @returns bool
   *   TRUE if the post count is below the limit.
   */
  private function isPostCountBelowLimit(): bool {
    $uid = $this->currentUser->id();
    $log_json_storage = $this->entityTypeManager->getStorage('log_json');

    $interval_seconds = $this->configFactory->get('decoupled_json_log.settings')->get('rate_limit.interval_seconds');
    Assert::integer($interval_seconds, 'Failed to get interval_seconds config!');
    $current_timestamp = $this->time->getCurrentTime();
    $rate_limit_interval_start = $current_timestamp - $interval_seconds;

    $log_json_query = $log_json_storage->getQuery()
      ->accessCheck(FALSE)
      ->condition('uid', $uid)
      ->condition('created', $rate_limit_interval_start, '>=');
    $log_json_count = $log_json_query->count()->execute();

    if ($this->currentUser->isAnonymous()) {
      $rate_limit = $this->configFactory->get('decoupled_json_log.settings')->get('rate_limit.count_anon');
    }
    else {
      $rate_limit = $this->configFactory->get('decoupled_json_log.settings')->get('rate_limit.count_auth');
    }
    Assert::integer($rate_limit, 'Could not get config rate_limit!');

    return $log_json_count <= $rate_limit;
  }

}

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

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