turnstile

Drupal paywall plugin
Log | Files | Refs | README | LICENSE

TurnstileSettingsForm.php (7778B)


      1 <?php
      2 
      3 namespace Drupal\taler_turnstile\Form;
      4 
      5 use Drupal\Core\Form\ConfigFormBase;
      6 use Drupal\Core\Form\FormStateInterface;
      7 use Drupal\Core\Config\ConfigFactoryInterface;
      8 use Drupal\Core\Entity\EntityTypeManagerInterface;
      9 use Drupal\taler_turnstile\TalerBackendErrorKind;
     10 use Drupal\taler_turnstile\TurnstileFieldManager;
     11 use Drupal\taler_turnstile\TalerMerchantApiService;
     12 use Symfony\Component\DependencyInjection\ContainerInterface;
     13 
     14 /**
     15  * Configure GNU Taler Turnstile settings.
     16  */
     17 class TurnstileSettingsForm extends ConfigFormBase {
     18 
     19   /**
     20    * The entity type manager.
     21    *
     22    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
     23    */
     24   protected $entityTypeManager;
     25 
     26   /**
     27    * The Turnstile field manager.
     28    *
     29    * @var \Drupal\taler_turnstile\TurnstileFieldManager
     30    */
     31   protected $fieldManager;
     32 
     33   /**
     34    * The Taler Merchant API service.
     35    *
     36    * @var \Drupal\taler_turnstile\TalerMerchantApiService
     37    */
     38   protected $apiService;
     39 
     40   /**
     41    * Constructs a TurnstileSettingsForm object.
     42    *
     43    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
     44    *   The factory for configuration objects.
     45    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
     46    *   The entity type manager.
     47    * @param \Drupal\taler_turnstile\TurnstileFieldManager $field_manager
     48    *   The field manager.
     49    * @param \Drupal\taler_turnstile\TalerMerchantApiService $api_service
     50    *   The API service.
     51    */
     52   public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, TurnstileFieldManager $field_manager, TalerMerchantApiService $api_service) {
     53     parent::__construct($config_factory);
     54     $this->entityTypeManager = $entity_type_manager;
     55     $this->fieldManager = $field_manager;
     56     $this->apiService = $api_service;
     57   }
     58 
     59   /**
     60    * {@inheritdoc}
     61    */
     62   public static function create(ContainerInterface $container) {
     63     return new static(
     64       $container->get('config.factory'),
     65       $container->get('entity_type.manager'),
     66       $container->get('taler_turnstile.field_manager'),
     67       $container->get('taler_turnstile.api_service')
     68     );
     69   }
     70 
     71   /**
     72    * {@inheritdoc}
     73    */
     74   protected function getEditableConfigNames() {
     75     return ['taler_turnstile.settings'];
     76   }
     77 
     78   /**
     79    * {@inheritdoc}
     80    */
     81   public function getFormId() {
     82     return 'taler_turnstile_settings_form';
     83   }
     84 
     85   /**
     86    * {@inheritdoc}
     87    */
     88   public function buildForm(array $form, FormStateInterface $form_state) {
     89     $config = $this->config('taler_turnstile.settings');
     90 
     91     // Get all available content types.
     92     $content_types = $this->entityTypeManager->getStorage('node_type')->loadMultiple();
     93     $type_options = [];
     94     foreach ($content_types as $type) {
     95       $type_options[$type->id()] = $type->label();
     96     }
     97 
     98     $form['enabled_content_types'] = [
     99       '#type' => 'checkboxes',
    100       '#title' => $this->t('Enabled content types'),
    101       '#description' => $this->t('Select which content types should have the price field and be subject to paywall transformation.'),
    102       '#options' => $type_options,
    103       '#default_value' => $config->get('enabled_content_types') ?: [],
    104     ];
    105 
    106     $form['payment_backend_url'] = [
    107       '#type' => 'url',
    108       '#title' => $this->t('Payment backend URL'),
    109       '#description' => $this->t('HTTP URL for the payment backend service.'),
    110       '#default_value' => $config->get('payment_backend_url') ?: '',
    111       '#maxlength' => 255,
    112     ];
    113 
    114     $form['access_token'] = [
    115       '#type' => 'textfield',
    116       '#title' => $this->t('Access token'),
    117       '#description' => $this->t('Access token for authenticating with the payment backend.'),
    118       '#default_value' => $config->get('access_token') ?: '',
    119       '#maxlength' => 255,
    120     ];
    121 
    122     $form['grant_access_on_error'] = [
    123       '#type' => 'checkbox',
    124       '#title' => $this->t('Disable Turnstile when payment backend is unavailable'),
    125       '#description' => $this->t('Allows users gratis access when Turnstile is unable to communicate with the GNU Taler merchant backend. Use this setting to avoid exposing users to configuration errors.'),
    126       '#default_value' => $config->get('grant_access_on_error') ?: '',
    127     ];
    128 
    129     return parent::buildForm($form, $form_state);
    130   }
    131 
    132 
    133   /**
    134    * {@inheritdoc}
    135    */
    136   public function validateForm(array &$form, FormStateInterface $form_state) {
    137     parent::validateForm($form, $form_state);
    138     $payment_backend_url = $form_state->getValue('payment_backend_url');
    139     $access_token = $form_state->getValue('access_token');
    140 
    141     // Validate the URL only if one was actually supplied; leaving
    142     // the backend unconfigured is an intentional path (covered by
    143     // the "warn but don't block" branch at the bottom).
    144     if (!empty($payment_backend_url)) {
    145       if (!str_ends_with($payment_backend_url, '/')) {
    146         $form_state->setErrorByName('payment_backend_url',
    147                                     $this->t('Payment backend URL must end with a "/".'));
    148         return;
    149       }
    150       $cfg_result = $this->apiService->checkConfig($payment_backend_url);
    151       if (!$cfg_result->isOk()) {
    152         $form_state->setErrorByName(
    153           'payment_backend_url',
    154           $cfg_result->toUserMessage($payment_backend_url)
    155         );
    156         return;
    157       }
    158     }
    159 
    160     if ( (!empty($access_token)) &&
    161          (!str_starts_with($access_token, 'secret-token:')) ) {
    162       $form_state->setErrorByName('access_token',
    163                                   $this->t('Access token must begin with a "secret-token:".'));
    164       return;
    165     }
    166 
    167     // Only verify the access token when both fields are present;
    168     // otherwise we hit the warn-but-don't-block branch below.
    169     // AUTH_FAILED is attached to the access_token field; every other
    170     // failure (unreachable, 5xx, unknown instance, ...) is attached
    171     // to the URL field.
    172     if (!empty($payment_backend_url) && !empty($access_token)) {
    173       $access_result = $this->apiService->checkAccess($payment_backend_url, $access_token);
    174       if (!$access_result->isOk()) {
    175         $field = ($access_result->kind === TalerBackendErrorKind::AUTH_FAILED)
    176           ? 'access_token'
    177           : 'payment_backend_url';
    178         $form_state->setErrorByName(
    179           $field,
    180           $access_result->toUserMessage($payment_backend_url)
    181         );
    182         return;
    183       }
    184     }
    185 
    186     // If the merchant backend is not configured at all, we allow the user
    187     // to save the settings. But, we warn them if they did not set
    188     // grant_access_on_error.
    189     $grant_access_on_error = $form_state->getValue('grant_access_on_error');
    190     if ( (! $grant_access_on_error) &&
    191          (empty($payment_backend_url) ||
    192           empty($access_token)) ) {
    193       $this->messenger()->addWarning(
    194         $this->t('Warning: Merchant backend is not configured correctly. To keep the site working, you probably should set the "Disable Turnstile when payment backend is unavailable" option!'));
    195       return;
    196     }
    197   }
    198 
    199   /**
    200    * {@inheritdoc}
    201    */
    202   public function submitForm(array &$form, FormStateInterface $form_state) {
    203     $config = $this->config('taler_turnstile.settings');
    204 
    205     $payment_backend_url = $form_state->getValue('payment_backend_url');
    206     $access_token = $form_state->getValue('access_token');
    207     $new_enabled_types = array_values(array_filter($form_state->getValue('enabled_content_types')));
    208     $grant_access_on_error = $form_state->getValue('grant_access_on_error');
    209 
    210     // Save configuration.
    211     $config->set('enabled_content_types', $new_enabled_types);
    212     $config->set('payment_backend_url', $payment_backend_url);
    213     $config->set('access_token', $access_token);
    214     $config->set('grant_access_on_error', $grant_access_on_error);
    215     $config->save();
    216 
    217     parent::submitForm($form, $form_state);
    218   }
    219 }