CaptchaSettingsForm.php 11.5 KB
Newer Older
1
2
3
4
<?php

namespace Drupal\captcha\Form;

5
use Drupal\captcha\Service\CaptchaService;
6
use Drupal\Core\Cache\CacheBackendInterface;
7
use Drupal\Core\Config\ConfigFactoryInterface;
8
use Drupal\Core\Extension\ModuleHandlerInterface;
9
10
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
Sascha Grossenbacher's avatar
Sascha Grossenbacher committed
11
use Drupal\Core\Url;
12
13
14
15
16
17
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Displays the captcha settings form.
 */
class CaptchaSettingsForm extends ConfigFormBase {
18

19
  /**
20
   * The cache backend.
Lukas Schneider's avatar
Lukas Schneider committed
21
   *
22
   * @var \Drupal\Core\Cache\CacheBackendInterface
23
   */
24
  protected $cacheBackend;
25

26
27
28
29
30
31
32
  /**
   * The CAPTCHA helper service.
   *
   * @var \Drupal\captcha\Service\CaptchaService
   */
  protected $captchaService;

33
  /**
34
35
36
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
37
38
39
   */
  protected $moduleHandler;

40
  /**
41
42
43
44
45
46
   * Constructs a \Drupal\captcha\Form\CaptchaSettingsForm object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The factory for configuration objects.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   Cache backend instance to use.
47
48
   * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler
   *   Module handler.
49
   */
50
  public function __construct(ConfigFactoryInterface $config_factory, CacheBackendInterface $cache_backend, ModuleHandlerInterface $moduleHandler, CaptchaService $captcha_service) {
51
    parent::__construct($config_factory);
52
    $this->cacheBackend = $cache_backend;
53
    $this->moduleHandler = $moduleHandler;
54
    $this->captchaService = $captcha_service;
55
56
57
58
59
60
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
61
62
    return new static(
      $container->get('config.factory'),
63
      $container->get('cache.default'),
64
65
      $container->get('module_handler'),
      $container->get('captcha.helper')
66
    );
67
68
  }

69
70
71
72
73
74
75
  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return ['captcha.settings'];
  }

76
77
78
  /**
   * Implements \Drupal\Core\Form\FormInterface::getFormID().
   */
Lukas Schneider's avatar
Lukas Schneider committed
79
  public function getFormId() {
80
81
82
83
84
85
86
87
88
89
90
91
    return 'captcha_settings';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this->config('captcha.settings');
    module_load_include('inc', 'captcha');
    module_load_include('inc', 'captcha', 'captcha.admin');

    // Configuration of which forms to protect, with what challenge.
92
    $form['form_protection'] = [
93
94
95
96
      '#type' => 'details',
      '#title' => $this->t('Form protection'),
      '#description' => $this->t("Select the challenge type you want for each of the listed forms (identified by their so called <em>form_id</em>'s). You can easily add arbitrary forms with the textfield at the bottom of the table or with the help of the option <em>Add CAPTCHA administration links to forms</em> below."),
      '#open' => TRUE,
97
    ];
98

99
    $form['form_protection']['default_challenge'] = [
100
101
      '#type' => 'select',
      '#title' => $this->t('Default challenge type'),
102
      '#description' => $this->t('Select the default challenge type for CAPTCHAs. This can be overridden for each form if desired.'),
103
      '#options' => $this->captchaService->getAvailableChallengeTypes(FALSE),
104
      '#default_value' => $config->get('default_challenge'),
105
    ];
106

107
108
109
110
    // Option for enabling CAPTCHA for all forms.
    $form['form_protection']['enabled_default'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Default challenge on non-listed forms.'),
111
      '#description' => $this->t('Enable CAPTCHA for every form not listed here'),
112
113
      '#default_value' => $config->get('enabled_default'),
    ];
114
    // Field for the CAPTCHA administration mode.
115
    $form['form_protection']['administration_mode'] = [
116
117
      '#type' => 'checkbox',
      '#title' => $this->t('Add CAPTCHA administration links to forms'),
tonnosf's avatar
tonnosf committed
118
      '#default_value' => $config->get('administration_mode'),
119
      '#description' => $this->t('This option makes it easy to manage CAPTCHA settings on forms. When enabled, users with the <em>administer CAPTCHA settings</em> permission will see a fieldset with CAPTCHA administration links on all forms, except on administrative pages.'),
120
    ];
121
    // Field for the CAPTCHAs on admin pages.
122
    $form['form_protection']['allow_on_admin_pages'] = [
123
124
      '#type' => 'checkbox',
      '#title' => $this->t('Allow CAPTCHAs and CAPTCHA administration links on administrative pages'),
tonnosf's avatar
tonnosf committed
125
      '#default_value' => $config->get('allow_on_admin_pages'),
126
      '#description' => $this->t("This option makes it possible to add CAPTCHAs to forms on administrative pages. CAPTCHAs are disabled by default on administrative pages (which shouldn't be accessible to untrusted users normally) to avoid the related overhead. In some situations, e.g. in the case of demo sites, it can be useful to allow CAPTCHAs on administrative pages."),
127
    ];
128
129
130

    // Button for clearing the CAPTCHA placement cache.
    // Based on Drupal core's "Clear all caches" (performance settings page).
131
    $form['form_protection']['placement_caching'] = [
132
      '#type' => 'item',
133
134
      '#title' => $this->t('CAPTCHA placement caching'),
      '#description' => $this->t('For efficiency, the positions of the CAPTCHA elements in each of the configured forms are cached. Most of the time, the structure of a form does not change and it would be a waste to recalculate the positions every time. Occasionally however, the form structure can change (e.g. during site building) and clearing the CAPTCHA placement cache can be required to fix the CAPTCHA placement.'),
135
136
    ];
    $form['form_protection']['placement_caching']['placement_cache_clear'] = [
137
      '#type' => 'submit',
138
      '#value' => $this->t('Clear the CAPTCHA placement cache'),
139
140
      '#submit' => ['::clearCaptchaPlacementCacheSubmit'],
    ];
141
142

    // Configuration option for adding a CAPTCHA description.
143
    $form['add_captcha_description'] = [
144
      '#type' => 'checkbox',
145
146
      '#title' => $this->t('Add a description to the CAPTCHA'),
      '#description' => $this->t('Add a configurable description to explain the purpose of the CAPTCHA to the visitor.'),
tonnosf's avatar
tonnosf committed
147
      '#default_value' => $config->get('add_captcha_description'),
148
149
    ];
    $form['description'] = [
tonnosf's avatar
tonnosf committed
150
151
152
153
154
      '#type' => 'textfield',
      '#title' => $this->t('Challenge description'),
      '#description' => $this->t('Configurable description of the CAPTCHA. An empty entry will reset the description to default.'),
      '#default_value' => _captcha_get_description(),
      '#maxlength' => 256,
155
      '#attributes' => ['id' => 'edit-captcha-description-wrapper'],
156
157
      '#states' => [
        'visible' => [
158
159
160
          ':input[name="add_captcha_description"]' => [
            'checked' => TRUE,
          ],
161
162
        ],
      ],
163
    ];
164
165

    // Option for case sensitive/insensitive validation of the responses.
166
    $form['default_validation'] = [
167
      '#type' => 'radios',
168
169
      '#title' => $this->t('Default CAPTCHA validation'),
      '#description' => $this->t('Define how the response should be processed by default. Note that the modules that provide the actual challenges can override or ignore this.'),
170
      '#options' => [
171
172
        CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE => $this->t('Case sensitive validation: the response has to exactly match the solution.'),
        CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE => $this->t('Case insensitive validation: lowercase/uppercase errors are ignored.'),
173
      ],
tonnosf's avatar
tonnosf committed
174
      '#default_value' => $config->get('default_validation'),
175
    ];
176
177
178

    // Field for CAPTCHA persistence.
    // TODO for D7: Rethink/simplify the explanation and UI strings.
179
    $form['persistence'] = [
180
      '#type' => 'radios',
181
      '#title' => $this->t('Persistence'),
tonnosf's avatar
tonnosf committed
182
      '#default_value' => $config->get('persistence'),
183
      '#options' => [
184
185
186
187
        CAPTCHA_PERSISTENCE_SHOW_ALWAYS => $this->t('Always add a challenge.'),
        CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE => $this->t('Omit challenges in a multi-step/preview workflow once the user successfully responds to a challenge.'),
        CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE => $this->t('Omit challenges on a form type once the user successfully responds to a challenge on a form of that type.'),
        CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL => $this->t('Omit challenges on all forms once the user successfully responds to any challenge on the site.'),
188
      ],
189
      '#description' => $this->t('Define if challenges should be omitted during the rest of a session once the user successfully responds to a challenge.'),
190
    ];
191
192

    // Enable wrong response counter.
193
    $form['enable_stats'] = [
194
195
      '#type' => 'checkbox',
      '#title' => $this->t('Enable statistics'),
196
      '#description' => $this->t('Keep CAPTCHA related counters in the <a href=":statusreport">status report</a>. Note that this comes with a performance penalty as updating the counters results in clearing the variable cache.', [
197
        ':statusreport' => Url::fromRoute('system.status')->toString(),
198
      ]),
tonnosf's avatar
tonnosf committed
199
      '#default_value' => $config->get('enable_stats'),
200
    ];
201
202

    // Option for logging wrong responses.
203
    $form['log_wrong_responses'] = [
204
205
      '#type' => 'checkbox',
      '#title' => $this->t('Log wrong responses'),
Sascha Grossenbacher's avatar
Sascha Grossenbacher committed
206
      '#description' => $this->t('Report information about wrong responses to the log.'),
tonnosf's avatar
tonnosf committed
207
      '#default_value' => $config->get('log_wrong_responses'),
208
    ];
209

Sascha Grossenbacher's avatar
Sascha Grossenbacher committed
210
    // Replace the description with a link if dblog.module is enabled.
211
    if ($this->moduleHandler->moduleExists('dblog')) {
212
      $form['log_wrong_responses']['#description'] = $this->t('Report information about wrong responses to the <a href=":dblog">log</a>.', [
213
        ':dblog' => Url::fromRoute('dblog.overview')->toString(),
214
      ]);
Sascha Grossenbacher's avatar
Sascha Grossenbacher committed
215
    }
216
217

    // Submit button.
218
219
    $form['actions'] = ['#type' => 'actions'];
    $form['actions']['submit'] = [
220
      '#type' => 'submit',
221
      '#value' => $this->t('Save configuration'),
222
    ];
223
224
225
226
227
228
229
230

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
231
    $config = $this->config('captcha.settings');
232
233
234
    $config->set('administration_mode', $form_state->getValue('administration_mode'));
    $config->set('allow_on_admin_pages', $form_state->getValue('allow_on_admin_pages'));
    $config->set('default_challenge', $form_state->getValue('default_challenge'));
235
    $config->set('enabled_default', $form_state->getValue('enabled_default'));
236
237

    // CAPTCHA description stuff.
238
    $config->set('add_captcha_description', $form_state->getValue('add_captcha_description'));
239
    // Save (or reset) the CAPTCHA descriptions.
240
    $config->set('description', $form_state->getValue('description'));
241

242
243
244
245
    $config->set('default_validation', $form_state->getValue('default_validation'));
    $config->set('persistence', $form_state->getValue('persistence'));
    $config->set('enable_stats', $form_state->getValue('enable_stats'));
    $config->set('log_wrong_responses', $form_state->getValue('log_wrong_responses'));
246
    $config->save();
247
    $this->messenger()->addStatus($this->t('The CAPTCHA settings have been saved.'));
248

249
    parent::submitForm($form, $form_state);
250
251
252
253
254
255
256
  }

  /**
   * Submit callback; clear CAPTCHA placement cache.
   *
   * @param array $form
   *   Form structured array.
257
   * @param Drupal\Core\Form\FormStateInterface $form_state
258
   *   Form state structured array.
259
   */
260
261
  public function clearCaptchaPlacementCacheSubmit(array $form, FormStateInterface $form_state) {
    $this->cacheBackend->delete('captcha_placement_map_cache');
262
    $this->messenger()->addMessage($this->t('Cleared the CAPTCHA placement cache.'));
263
  }
264

265
}