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 }