autoban-8.x-1.x-dev/src/Form/AutobanFormBase.php

src/Form/AutobanFormBase.php
<?php

namespace Drupal\autoban\Form;

use Drupal\Component\Utility\Html;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Database;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\autoban\AutobanUtils;
use Drupal\autoban\Controller\AutobanController;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * @file
 * Class AutobanFormBase.
 *
 * @package Drupal\autoban\Form
 *
 * @ingroup autoban
 */

/**
 * Autoban base form for add and edit.
 */
class AutobanFormBase extends EntityForm {

  /**
   * Define AutobanFormBase class.
   */

  /**
   * Entity Type Manager variable.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   *   Define EntityTypeManager variable.
   */
  protected $entityTypeManager;

  /**
   * Config factory variable.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  protected $config;

  /**
   * The autoban object.
   *
   * @var \Drupal\autoban\Controller\AutobanController
   */
  protected $autoban;

  /**
   * Construct the AutobanFormBase.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   An entity type manager interface for the autoban entity type.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config
   *   Store ConfigFactoryInterface manager.
   * @param \Drupal\autoban\Controller\AutobanController $autoban
   *   Autoban object.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, ConfigFactoryInterface $config, AutobanController $autoban) {
    $this->entityTypeManager = $entity_type_manager;
    $this->config = $config;
    $this->autoban = $autoban;
  }

  /**
   * Factory method for AutobanFormBase.
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('config.factory'),
      $container->get('autoban')
    );
  }

  /**
   * Overrides Drupal\Core\Entity\EntityFormController::form().
   *
   * Builds the entity add/edit form.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   An associative array containing the current state of the form.
   * @param string $rule
   *   Rule ID (optional).
   *
   * @return array
   *   An associative array containing the autoban add/edit form.
   */
  public function buildForm(array $form, FormStateInterface $form_state, $rule = NULL) {
    $form = parent::buildForm($form, $form_state);
    $params = $this->getRequest()->query->all();
    if ($rule) {
      $autoban = $this->entityTypeManager->getStorage('autoban')->load($rule);
      if (!$autoban) {
        throw new NotFoundHttpException();
      }
    }
    else {
      $autoban = $this->entity;
    }
    $controller = $this->autoban;
    $is_new = $autoban->isNew() || $rule;

    $rule_type_value = $is_new ? AutobanUtils::AUTOBAN_RULE_MANUAL : $autoban->rule_type;
    $form['rule_type'] = [
      '#type' => 'hidden',
      '#value' => $rule_type_value,
    ];

    if (!empty($rule_type_value)) {
      $form['rule_type_array'] = [
        '#markup' => $this->t('Rule type: @type', ['@type' => $controller->ruleTypeList($rule_type_value)]),
      ];
    }

    $form['id'] = [
      '#type' => 'machine_name',
      '#title' => $this->t('Id'),
      '#description' => $this->t('Unique rules name'),
      '#default_value' => $is_new ? $this->newDefaultId() : $autoban->id(),
      '#maxlength' => 64,
      '#machine_name' => [
        'exists' => [$this, 'exists'],
        'replace_pattern' => '([^a-z0-9_]+)|(^custom$)',
        'error' => $this->t('Must be unique, and can only contain lowercase letters, numbers, and underscores. Additionally, it can not be the reserved word "custom".'),
      ],
      '#disabled' => !$is_new,
    ];

    // Type current groups.
    $dblog_type_exclude = $this->config('autoban.settings')->get('autoban_dblog_type_exclude') ?: "autoban\ncron\nphp\nsystem\nuser";
    $query = Database::getConnection()->select('watchdog', 'log');
    $query->addField('log', 'type');
    $query->condition('type', explode(PHP_EOL, $dblog_type_exclude), 'NOT IN');
    $query->orderBy('type');
    $all_groups = $query->execute()->fetchAllKeyed(0, 0);

    array_walk($all_groups, function (&$item, $key) {
      $item = "<span>$item</span>";
    });

    $default_type = $autoban->type;
    if (empty($default_type) && !empty($params['type'])) {
      $default_type = $params['type'];
    }

    $form['type'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Type'),
      '#description' => implode(', ', $all_groups),
      '#maxlength' => 255,
      '#default_value' => $default_type,
      '#required' => TRUE,
    ];

    $default_message = $autoban->message;
    if (empty($default_message) && !empty($params['message'])) {
      $default_message = Html::decodeEntities($params['message']);
    }

    $query_mode = $this->config('autoban.settings')->get('autoban_query_mode') ?: 'like';
    $query_mode_message = strtoupper($query_mode);
    $use_wildcards = $this->config('autoban.settings')->get('autoban_use_wildcards') ?: FALSE;
    $use_wildcards_message = $use_wildcards ? $this->t('yes') : $this->t('no');

    $form['message'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Message pattern'),
      '#description' => $this->t('Dblog message @query_mode pattern. Use delimiter "|" for multiple values. Use wildcards: @use_wildcards_message.', [
        '@query_mode' => $query_mode_message,
        '@use_wildcards_message' => $use_wildcards_message,
      ]),
      '#maxlength' => 255,
      '#default_value' => $default_message,
      '#required' => TRUE,
    ];

    $form['referer'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Referrer pattern'),
      '#description' => $this->t('URL referrer pattern.'),
      '#maxlength' => 255,
      '#default_value' => $autoban->referer,
      '#required' => FALSE,
    ];

    $thresholds_config = $this->config('autoban.settings')->get('autoban_thresholds');
    $thresholds = !empty($thresholds_config) ?
    explode(PHP_EOL, $thresholds_config)
    : [1, 2, 3, 5, 10, 20, 50, 100];
    if (empty($autoban->threshold)) {
      $last_threshold = $this->config('autoban.settings')->get('autoban_threshold_last');
      if ($last_threshold && in_array($last_threshold, $thresholds)) {
        $autoban->threshold = $last_threshold;
      }
    }

    $form['threshold'] = [
      '#type' => 'select',
      '#title' => $this->t('Threshold'),
      '#description' => $this->t('The threshold number of the log entries.'),
      '#default_value' => $autoban->threshold,
      '#options' => array_combine($thresholds, $thresholds),
      '#required' => TRUE,
    ];

    $windows_config = $this->config('autoban.settings')->get('autoban_windows');
    $windows = !empty($windows_config) ?
      explode(PHP_EOL, $windows_config)
      : ['1 hour ago', '1 day ago', '1 week ago', '1 month ago', '1 year ago'];
    if (empty($autoban->window)) {
      $last_window = $this->config('autoban.settings')->get('autoban_window_last');
      if ($last_window && in_array($last_window, $windows)) {
        $autoban->window = $last_window;
      }
    }
    if (empty($autoban->window)) {
      $default_window = $this->config('autoban.settings')->get('autoban_window_default');
      if ($default_window && in_array($default_window, $windows)) {
        $autoban->window = $default_window;
      }
    }

    $form['window'] = [
      '#type' => 'select',
      '#title' => $this->t('Window'),
      '#description' => $this->t('Relative time window for log entries
        this rule should run against. For example, a window of "1 hour ago"
        means the rule will be run against log entries that occurred within the
        last hour. Selecting "None" means that all log entries will be checked.
        <em><small>NOTE: if you are using a ban provider that supports IP ban
        expiry (e.g. Advanced Ban), you may want to choose a window that is
        equal to or less than the default IP ban expiry duration to
        ensure bans expire as expected.</small></em>'),
      '#default_value' => $autoban->window ?? 'none',
      '#options' => ['none' => $this->t('None')] + array_combine($windows, $windows),
      '#required' => TRUE,
    ];

    $form['user_type'] = [
      '#type' => 'select',
      '#title' => $this->t('User type'),
      '#description' => $this->t('User type: anonymous, authenticated or any.'),
      '#default_value' => $autoban->user_type ?: 0,
      '#options' => $controller->userTypeList(),
      '#required' => TRUE,
    ];

    // Retrieve Ban manager list.
    $providers = [];
    $banManagerList = $controller->getBanProvidersList();
    if (!empty($banManagerList)) {
      foreach ($banManagerList as $id => $item) {
        $providers[$id] = $item['name'];
      }
    }
    else {
      $this->messenger()->addMessage(
        $this->t('List ban providers is empty. You have to enable at least one Autoban providers module.'),
        'warning'
      );
    }

    // For a single provider.
    if ($autoban->isNew() && count($providers) > 0) {
      if (count($providers) == 1) {
        $autoban->provider = array_keys($providers)[0];
      }
      else {
        $last_provider = $this->config('autoban.settings')->get('autoban_provider_last');
        if ($last_provider && isset($providers[$last_provider])) {
          $autoban->provider = $last_provider;
        }
      }
    }

    $form['provider'] = [
      '#type' => 'select',
      '#title' => $this->t('IP ban provider'),
      '#default_value' => $autoban->provider,
      '#options' => $providers,
      '#required' => TRUE,
    ];

    $destination = $this->getDestinationArray();
    $cancel_url = !empty($destination['destination']) && Url::fromRoute('<current>')->toString() != $destination['destination'] ?
      Url::fromUserInput($destination['destination']) : Url::fromRoute('entity.autoban.list');

    $form['actions']['cancel'] = [
      '#type' => 'link',
      '#title' => $this->t('Cancel'),
      '#url' => $cancel_url,
      '#attributes' => [
        'class' => ['button'],
      ],
      '#weight' => 100,
    ];

    $form['#attached']['library'][] = 'autoban/form';

    return $form;
  }

  /**
   * Checks for an existing autoban rule.
   *
   * @param string|int $entity_id
   *   The entity ID.
   * @param array $element
   *   The form element.
   * @param Drupal\Core\Form\FormStateInterface $form_state
   *   The form state.
   *
   * @return bool
   *   TRUE if this format already exists, FALSE otherwise.
   */
  public function exists($entity_id, array $element, FormStateInterface $form_state) {
    $query = $this->entityTypeManager->getStorage('autoban')->getQuery();
    $result = $query->condition('id', $element['#field_prefix'] . $entity_id)->accessCheck(FALSE)
      ->execute();

    return (bool) $result;
  }

  /**
   * Generate default ID for new item.
   *
   * @return string
   *   Default ID.
   */
  public function newDefaultId() {
    $query = $this->entityTypeManager->getStorage('autoban')->getQuery();
    $query->condition('rule_type', AutobanUtils::AUTOBAN_RULE_AUTO, '=');
    $cnt_auto = $query->accessCheck(TRUE)->count()->execute();
    $query = $this->entityTypeManager->getStorage('autoban')->getQuery();
    $cnt_total = $query->accessCheck(TRUE)->count()->execute();

    $next = $cnt_total - $cnt_auto + 1;
    $entity_id = "rule$next";
    $result = $query->condition('id', $entity_id)->accessCheck(FALSE)
      ->execute();
    $exists = (bool) $result;

    return $exists ? '' : $entity_id;
  }

  /**
   * Overrides Drupal\Core\Entity\EntityFormController::actions().
   *
   * To set the submit button text, we need to override actions().
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   An associative array containing the current state of the form.
   *
   * @return array
   *   An array of supported actions for the current entity form.
   */
  protected function actions(array $form, FormStateInterface $form_state) {
    $actions = parent::actions($form, $form_state);
    $actions['submit']['#value'] = $this->t('Save');
    return $actions;
  }

  /**
   * Overrides Drupal\Core\Entity\EntityFormController::save().
   *
   * Saves the entity. This is called after submit() has built the entity from
   * the form values. Do not override submit() as save() is the preferred
   * method for entity form controllers.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   An associative array containing the current state of the form.
   */
  public function save(array $form, FormStateInterface $form_state) {
    $last_threshold = $form_state->getValue('threshold');
    $last_window = $form_state->getValue('window');
    $last_provider = $form_state->getValue('provider');
    $this->config->getEditable('autoban.settings')
      ->set('autoban_threshold_last', $last_threshold)
      ->set('autoban_window_last', $last_window)
      ->set('autoban_provider_last', $last_provider)
      ->save();

    $autoban = $this->getEntity();
    $status = $autoban->save();
    $url = $autoban->toUrl();
    $edit_link = Link::fromTextAndUrl($this->t('Edit'), $url)->toString();

    if ($status == SAVED_UPDATED) {
      // If we edited an existing entity...
      $this->messenger()->addMessage($this->t('Autoban rule %label has been updated.',
        ['%label' => $autoban->id()]));
      $this->logger('autoban')->notice('Autoban rule %label has been updated.',
        ['%label' => $autoban->id(), 'link' => $edit_link]);
    }
    else {
      // If we created a new entity...
      $this->messenger()->addMessage($this->t('Autoban rule %label has been added.',
        ['%label' => $autoban->id()]));
      $this->logger('autoban')->notice('Autoban rule %label has been added.',
        ['%label' => $autoban->id(), 'link' => $edit_link]);
    }

    // Redirect the user back to the listing route after the save operation.
    $form_state->setRedirect('entity.autoban.list');
  }

}

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

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