<?php

/**
 * @file
 * Install, update and uninstall functions for the CAPTCHA module.
 */

use Drupal\captcha\Constants\CaptchaConstants;

/**
 * Implements hook_schema().
 */
function captcha_schema() {
  $schema['captcha_sessions'] = [
    'description' => 'Stores the data about CAPTCHA sessions (solution, IP address, timestamp, ...).',
    'fields' => [
      'csid' => [
        'description' => 'CAPTCHA session ID.',
        'type' => 'serial',
        'not null' => TRUE,
      ],
      'token' => [
        'description' => 'One time CAPTCHA token.',
        'type' => 'varchar',
        'length' => 64,
        'not null' => FALSE,
      ],
      'uid' => [
        'description' => "User's {users}.uid.",
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ],
      'sid' => [
        'description' => "Session ID of the user.",
        'type' => 'varchar',
        'length' => 64,
        'not null' => TRUE,
        'default' => '',
      ],
      'ip_address' => [
        'description' => 'IP address of the visitor.',
        'type' => 'varchar',
        'length' => 128,
        'not null' => FALSE,
      ],
      'timestamp' => [
        'description' => 'A Unix timestamp indicating when the challenge was generated.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ],
      'form_id' => [
        'description' => 'The form_id of the form where the CAPTCHA is added to.',
        'type' => 'varchar',
        'length' => 128,
        'not null' => TRUE,
      ],
      'solution' => [
        'description' => 'Solution of the challenge.',
        'type' => 'varchar',
        'length' => 128,
        'not null' => TRUE,
        'default' => '',
      ],
      'status' => [
        'description' => 'Status of the CAPTCHA session (unsolved, solved, ...)',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ],
      'attempts' => [
        'description' => 'The number of attempts.',
        'type' => 'int',
        'not null' => TRUE,
        'default' => 0,
      ],
    ],
    'primary key' => ['csid'],
    'indexes' => [
      'csid_ip' => ['csid', 'ip_address'],
    ],
  ];

  return $schema;
}

/**
 * Implements hook_requirements().
 */
function captcha_requirements($phase) {
  $requirements = [];
  $config = \Drupal::config('captcha.settings');

  if ($phase == 'runtime' && $config->get('enable_stats')) {
    // Show the wrong response counter in the status report.
    $requirements['captcha_wrong_response_counter'] = [
      'title' => \Drupal::translation()->translate('CAPTCHA'),
      'value' => \Drupal::translation()->formatPlural(
        \Drupal::state()->get('captcha.wrong_response_counter'),
        'Already 1 blocked form submission',
        'Already @count blocked form submissions'
      ),
      'severity' => REQUIREMENT_INFO,
    ];
  }
  return $requirements;
}

/**
 * Implements hook_install().
 */
function captcha_install() {

  if (!\Drupal::service('config.installer')->isSyncing() && \Drupal::moduleHandler()->moduleExists('node')) {
    $form_ids = [];
    $label = [];
    // Add form_ids of all currently known node types too.
    foreach (node_type_get_names() as $type => $name) {
      $form_ids[] = 'node_' . $type . '_form';
      $label[] = 'node_' . $type . '_form';
    }

    $captcha_storage = \Drupal::entityTypeManager()
      ->getStorage('captcha_point');
    foreach ($form_ids as $index => $form_id) {
      $values = [
        'label' => $label[$index],
        'formId' => $form_id,
        'captchaType' => CaptchaConstants::CAPTCHA_TYPE_DEFAULT,
        'status' => FALSE,
      ];
      $captcha_storage->create($values)->save();
    }
  }

}

/**
 * Implements hook_update_N().
 */
function captcha_update_8901(&$sandbox) {
  $entityType = \Drupal::entityTypeManager()
    ->getDefinition('captcha_point');

  if ($entityType) {
    \Drupal::entityDefinitionUpdateManager()
      ->installEntityType($entityType);
  }
}

/**
 * Implements hook_update_N().
 */
function captcha_update_8902(&$sandbox) {
  $query = \Drupal::entityQuery('captcha_point');
  $query->notExists('label');
  $entity_ids = $query->execute();

  if (!empty($entity_ids) && is_array($entity_ids)) {
    foreach ($entity_ids as $entity_id) {
      $captcha_point_id = $entity_id;
      $captcha_point = \Drupal::entityTypeManager()
        ->getStorage('captcha_point')
        ->load($captcha_point_id);
      $captcha_point->set('label', $captcha_point->getFormId());
      $captcha_point->save();
    }
  }
}

/**
 * Implements hook_update_N().
 *
 * Handle and delete "add_captcha_description".
 */
function captcha_update_8903(&$sandbox) {
  $config_factory = \Drupal::configFactory();
  $config = $config_factory->getEditable('captcha.settings');
  $addDescription = $config->get('add_captcha_description');
  // If description was disabled before, set 'description' to an empty string,
  // so it is disabled again in the newest version:
  if (!$addDescription) {
    $config->set('description', '')->save();
  }
  // Delete old config:
  $config->clear('add_captcha_description')->save();
}

/**
 * Several changes.
 *
 * Remove old configuration keys and map to new ones.
 */
function captcha_update_8904(&$sandbox) {
  // Update config:
  $config_factory = \Drupal::configFactory();
  $config = $config_factory->getEditable('captcha.settings');

  $config->set('administration_mode_on_admin_routes', FALSE);
  $config->set('enable_globally_on_admin_routes', FALSE);
  $config->set('enable_globally', $config->get('enabled_default'));

  if (!empty($config->get('allow_on_admin_pages')) && !empty($config->get('administration_mode'))) {
    $config->set('administration_mode_on_admin_routes', TRUE);
  }
  if (!empty($config->get('allow_on_admin_pages')) && !empty($config->get('enabled_default'))) {
    $config->set('enable_globally_on_admin_routes', TRUE);
  }
  $config
    ->clear('allow_on_admin_pages')
    ->clear('enabled_default')
    ->save();
}

/**
 * Add the captcha title, if the user has not set it manually yet.
 *
 * Note, that this is needed, because the update hook introducing the title
 * was originally implemented in the wrong install file (image_captcha.install).
 * See https://www.drupal.org/project/captcha/issues/3356063 where it was
 * wrongly added.
 */
function captcha_update_8905() {
  $captchaConfig = \Drupal::configFactory()->getEditable('captcha.settings');
  if ($captchaConfig->get('title') === NULL) {
    // Set the title in config, if it wasn't existing before:
    $captchaConfig->set('title', 'CAPTCHA')->save(TRUE);
  }
}

/**
 * Ensure caches are cleared with new module folder locations.
 */
function captcha_update_8906() {
  // Remove test modules if they're on the site. They won't rebuild.
  $extension = \Drupal::configFactory()->getEditable('core.extension');
  $modules = $extension->get('module');
  unset($modules['captcha_long_form_id_test']);
  unset($modules['captcha_test']);
  $extension->set('module', $modules);
  $extension->save();

  // Need to flush all caches due to module paths changing.
  drupal_flush_all_caches();
}

/**
 * Fix invalid config added in captcha_update_8906 (2.0.1)
 */
function captcha_update_8907() {
  // Remove test modules if they're on the site. They won't rebuild.
  $extension = \Drupal::configFactory()->getEditable('core.extension');

  // Remove invalid config added in 8906 and do the actual removal.
  if ($extension->get('modules') !== NULL) {
    $extension->clear('modules');

    $modules = $extension->get('module');
    unset($modules['captcha_long_form_id_test']);
    unset($modules['captcha_test']);
    $extension->set('module', $modules);

    $extension->save();

    // Need to flush all caches due to module paths changing.
    drupal_flush_all_caches();
  }
}
