gamify-1.1.x-dev/src/Plugin/Action/LogsSeriesHighFrequency.php

src/Plugin/Action/LogsSeriesHighFrequency.php
<?php

namespace Drupal\gamify\Plugin\Action;

use Drupal\Core\Form\FormStateInterface;
use Drupal\eca\Plugin\Action\ConfigurableActionBase;
use Drupal\gamify\Traits\DbLogResultTrait;

/**
 * Provide all tamper plugins as ECA actions.
 *
 * @Action(
 *   id = "gamify_logs_series_high_frequency",
 *   label = @Translation("Gamify: Detect in logs high frequent repetition serieses."),
 *   description = @Translation("Find user behahiour of high frequency repetition of same action, what might indicate a destructive behaviour.")
 * )
 */
class LogsSeriesHighFrequency extends ConfigurableActionBase {

  use DbLogResultTrait;

  /**
   * {@inheritdoc}
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException | \Drupal\Core\TypedData\Exception\MissingDataException
   */
  public function execute(): void {
    $dataKey = $this->configuration['eca_data'] ?? NULL;
    $entries = $dataKey ? $this->tokenServices->getTokenData($dataKey)->toArray() : NULL;

    $interim_result = [];
    if ($entries) {
      // If prev_result is multiple array, we combine it to a single result stack.
      if ($this->getNestingLevel($entries) === 3) {
        $combined = [];
        foreach ($entries as $entry) {
          $combined = array_merge($combined, $entry);
        }
        $entries = $entries[array_key_first($entries)];
      }

      $min_series_length = (int) $this->configuration['min_series_length'];
      $time_interval = (int) $this->configuration['time_interval'];
      if (count($entries) >= $min_series_length) {
        $interim_result = $this->seriesSearch($entries, $time_interval, $min_series_length);
      }
    }

    $this->tokenServices->addTokenData($this->configuration['eca_token_name'], $interim_result);
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration(): array {
    return [
      'eca_data' => '',
      'time_interval' => 10,
      'min_series_length' => 8,
      'eca_token_name' => '',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
    $form['eca_data'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Log entries to be filtered'),
      '#description' => $this->t('This field supports tokens.'),
      '#default_value' => $this->configuration['eca_data'],
      '#required' => TRUE,
      '#weight' => 10,
    ];
    $form['time_interval'] = [
      '#type' => 'number',
      '#title' => $this->t('Time interval (av.) between events'),
      '#description' => $this->t('Filter logs by RegEx or search string.'),
      '#default_value' => $this->configuration['time_interval'],
      '#required' => TRUE,
      '#weight' => 20,
    ];
    $form['min_series_length'] = [
      '#type' => 'number',
      '#title' => $this->t('Min Series length'),
      '#description' => $this->t('Tolerance concerning the min length of items in a series.'),
      '#default_value' => $this->configuration['min_series_length'],
      '#weight' => 30,
    ];
    $form['eca_token_name'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Result token name'),
      '#description' => $this->t('Provide a token name under which the tampered result will be made available for subsequent actions.'),
      '#default_value' => $this->configuration['eca_token_name'],
      '#required' => TRUE,
      '#weight' => 40,
    ];
    return parent::buildConfigurationForm($form, $form_state);
  }

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

  /**
   * Search for continued series in given log entries by time interval.
   *
   * @param array $entries
   *   Entries to search.
   * @param int $range
   *   Max duration between 2 log entries. If time diff is greater than $range
   *   a new series opens.
   * @param int $min_length
   *   Minimum number of entries in a serial.
   *
   * @return array
   *   An array of all series found.
   */
  public function seriesSearch(array $entries, int $time_span = 60, int $min_length = 3): array {
    $series = [];
    $collector = [];
    $serial_begin = 0;
    foreach ($entries as $wid => $entry) {
      $current_timestamp = (int) $entry['timestamp'];
      // First entry.
      if (!count($collector)) {
        $collector[$wid] = $entry;
        $serial_begin = $current_timestamp;
        continue;
      }
      // Follow-up entry.
      $serial_duration = $current_timestamp - $serial_begin;
      $divisor = count($collector) - 1;
      if (($divisor == 0) || ($serial_duration / $divisor) <= $time_span) {
        $collector[$wid] = $entry;
      }
      else {
        // Close current collection and create a serial.
        if (count($collector) >= $min_length) {
          $series[] = $collector;
        }

        // Restart with new serial.
        $collector = [$wid => $entry];
        $serial_begin = $current_timestamp;
      }
    }
    if (count($collector) >= $min_length) {
      $series[] = $collector;
    }
    return $series;
  }


}

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

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