turnstile

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

TurnstileSettingsForm.php (8353B)


      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\TurnstileFieldManager;
     10 use Drupal\taler_turnstile\TalerMerchantApiService;
     11 use Symfony\Component\DependencyInjection\ContainerInterface;
     12 
     13 /**
     14  * Configure GNU Taler Turnstile settings.
     15  */
     16 class TurnstileSettingsForm extends ConfigFormBase {
     17 
     18   /**
     19    * The entity type manager.
     20    *
     21    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
     22    */
     23   protected $entityTypeManager;
     24 
     25   /**
     26    * The Turnstile field manager.
     27    *
     28    * @var \Drupal\taler_turnstile\TurnstileFieldManager
     29    */
     30   protected $fieldManager;
     31 
     32   /**
     33    * The Taler Merchant API service.
     34    *
     35    * @var \Drupal\taler_turnstile\TalerMerchantApiService
     36    */
     37   protected $apiService;
     38 
     39   /**
     40    * Constructs a TurnstileSettingsForm object.
     41    *
     42    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
     43    *   The factory for configuration objects.
     44    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
     45    *   The entity type manager.
     46    * @param \Drupal\taler_turnstile\TurnstileFieldManager $field_manager
     47    *   The field manager.
     48    * @param \Drupal\taler_turnstile\TalerMerchantApiService $api_service
     49    *   The API service.
     50    */
     51   public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, TurnstileFieldManager $field_manager, TalerMerchantApiService $api_service) {
     52     parent::__construct($config_factory);
     53     $this->entityTypeManager = $entity_type_manager;
     54     $this->fieldManager = $field_manager;
     55     $this->apiService = $api_service;
     56   }
     57 
     58   /**
     59    * {@inheritdoc}
     60    */
     61   public static function create(ContainerInterface $container) {
     62     return new static(
     63       $container->get('config.factory'),
     64       $container->get('entity_type.manager'),
     65       $container->get('taler_turnstile.field_manager'),
     66       $container->get('taler_turnstile.api_service')
     67     );
     68   }
     69 
     70   /**
     71    * {@inheritdoc}
     72    */
     73   protected function getEditableConfigNames() {
     74     return ['taler_turnstile.settings'];
     75   }
     76 
     77   /**
     78    * {@inheritdoc}
     79    */
     80   public function getFormId() {
     81     return 'taler_turnstile_settings_form';
     82   }
     83 
     84   /**
     85    * {@inheritdoc}
     86    */
     87   public function buildForm(array $form, FormStateInterface $form_state) {
     88     $config = $this->config('taler_turnstile.settings');
     89 
     90     // Get all available content types.
     91     $content_types = $this->entityTypeManager->getStorage('node_type')->loadMultiple();
     92     $type_options = [];
     93     foreach ($content_types as $type) {
     94       $type_options[$type->id()] = $type->label();
     95     }
     96 
     97     $form['enabled_content_types'] = [
     98       '#type' => 'checkboxes',
     99       '#title' => $this->t('Enabled content types'),
    100       '#description' => $this->t('Select which content types should have the price field and be subject to paywall transformation.'),
    101       '#options' => $type_options,
    102       '#default_value' => $config->get('enabled_content_types') ?: [],
    103     ];
    104 
    105     $form['payment_backend_url'] = [
    106       '#type' => 'url',
    107       '#title' => $this->t('Payment backend URL'),
    108       '#description' => $this->t('HTTP URL for the payment backend service.'),
    109       '#default_value' => $config->get('payment_backend_url') ?: '',
    110       '#maxlength' => 255,
    111     ];
    112 
    113     $form['access_token'] = [
    114       '#type' => 'textfield',
    115       '#title' => $this->t('Access token'),
    116       '#description' => $this->t('Access token for authenticating with the payment backend.'),
    117       '#default_value' => $config->get('access_token') ?: '',
    118       '#maxlength' => 255,
    119     ];
    120 
    121     $form['grant_access_on_error'] = [
    122       '#type' => 'checkbox',
    123       '#title' => $this->t('Disable Turnstile when payment backend is unavailable'),
    124       '#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.'),
    125       '#default_value' => $config->get('grant_access_on_error') ?: '',
    126     ];
    127 
    128     return parent::buildForm($form, $form_state);
    129   }
    130 
    131 
    132   /**
    133    * {@inheritdoc}
    134    */
    135   public function validateForm(array &$form, FormStateInterface $form_state) {
    136     parent::validateForm($form, $form_state);
    137     $payment_backend_url = $form_state->getValue('payment_backend_url');
    138     $access_token = $form_state->getValue('access_token');
    139 
    140     if ( (!empty($payment_backend_url)) &&
    141          (!str_ends_with($payment_backend_url, '/')) )
    142     {
    143       $form_state->setErrorByName('payment_backend_url',
    144                                   $this->t('Payment backend URL must end with a "/".'));
    145       return;
    146     }
    147 
    148     if (! $this->apiService->checkConfig($payment_backend_url)) {
    149       $form_state->setErrorByName('payment_backend_url',
    150                                   $this->t('Invalid payment backend URL'));
    151       return;
    152     }
    153 
    154     if ( (!empty($access_token)) &&
    155          (!str_starts_with($access_token, 'secret-token:')) ) {
    156       $form_state->setErrorByName('access_token',
    157                                   $this->t('Access token must begin with a "secret-token:".'));
    158       return;
    159     }
    160 
    161     $http_status = $this->apiService->checkAccess($payment_backend_url, $access_token);
    162     switch ($http_status) {
    163       case 502:
    164         $form_state->setErrorByName('payment_backend_url',
    165                                     $this->t('Bad gateway (502) trying to access the merchant backend'));
    166         return;
    167       case 500:
    168         $form_state->setErrorByName('payment_backend_url',
    169                                     $this->t('Internal server error (500) of the merchant backend reported'));
    170         return;
    171       case 404:
    172         $form_state->setErrorByName('payment_backend_url',
    173                                     $this->t('The specified instance is unknown to the merchant backend'));
    174         return;
    175       case 403:
    176         $form_state->setErrorByName('access_token',
    177                                     $this->t('Access token not accepted by the merchant backend'));
    178         return;
    179       case 401:
    180         $form_state->setErrorByName('access_token',
    181                                     $this->t('Access token not accepted by the merchant backend'));
    182         return;
    183       case 204:
    184         // Empty order list is OK
    185         break;
    186       case 200:
    187         // Success is great
    188         break;
    189       case 0:
    190         $form_state->setErrorByName('payment_backend_url',
    191                                     $this->t('HTTP request failed'));
    192         return;
    193       default:
    194         $form_state->setErrorByName('payment_backend_url',
    195                                     $this->t('Unexpected response (@status) from merchant backend',
    196                                     [ '@status' => $http_status ]));
    197         return;
    198     } // end switch on HTTP status
    199 
    200     // If the merchant backend is not configured at all, we allow the user
    201     // to save the settings. But, we warn them if they did not set
    202     // grant_access_on_error.
    203     $grant_access_on_error = $form_state->getValue('grant_access_on_error');
    204     if ( (! $grant_access_on_error) &&
    205          (empty($payment_backend_url) ||
    206           empty($access_token)) ) {
    207       $this->messenger()->addWarning(
    208         $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!'));
    209       return;
    210     }
    211   }
    212 
    213   /**
    214    * {@inheritdoc}
    215    */
    216   public function submitForm(array &$form, FormStateInterface $form_state) {
    217     $config = $this->config('taler_turnstile.settings');
    218 
    219     $payment_backend_url = $form_state->getValue('payment_backend_url');
    220     $access_token = $form_state->getValue('access_token');
    221     $new_enabled_types = array_values(array_filter($form_state->getValue('enabled_content_types')));
    222     $grant_access_on_error = $form_state->getValue('grant_access_on_error');
    223 
    224     // Save configuration.
    225     $config->set('enabled_content_types', $new_enabled_types);
    226     $config->set('payment_backend_url', $payment_backend_url);
    227     $config->set('access_token', $access_token);
    228     $config->set('grant_access_on_error', $grant_access_on_error);
    229     $config->save();
    230 
    231     parent::submitForm($form, $form_state);
    232   }
    233 }