commit cde2563f6d36b5a74971c82eb0e060a3b1613d30
parent b0ba51442b71776779dcb09776e9257856fed10d
Author: Christian Grothoff <christian@grothoff.org>
Date: Sat, 11 Oct 2025 22:58:12 +0200
add subscription prices to settings, update TODO list
Diffstat:
2 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
@@ -46,14 +46,15 @@ Navigate to `/admin/config/content/Turnstile` to configure:
## TODO
-- add subscription prices to settings
-- actually get subscriptions to work: v1 contracts, etc.
- note that the logic is now more funky, customers could have a 50%-off
- subscription. So need to check if we have a subscription cookie
- set for a subscription that for the current category would give us
- a price of zero!
-- move HTTP logic from TurnstileSettingsForm to the API class!
-- use order expiration from merchant backend (with new v1.1 implementation)
+- REFACTOR: move HTTP logic from TurnstileSettingsForm to the API class!
+- actually get subscriptions to work:
+ * use new subscription prices( \Drupal::config('turnstile.settings')[$subscription_id][$currency_code] )
+ * empty means no choice to buy this subscription in this currency!
+ * when adding choice to buy subscription, need to ADD price of subscription + price of article with that subscription
+ for the purchase price!
+ * update session state to remember in session which subscriptions user proved to us and when they expire
+ * *if* user is about to buy an article for which under a non-expired subscription we have a price of 0, then skip payment
+- LATER: use order expiration from merchant backend (with new v1.1 implementation)
instead of hard-coding 1 day!
## How it Works
diff --git a/src/Form/TurnstileSettingsForm.php b/src/Form/TurnstileSettingsForm.php
@@ -12,6 +12,7 @@ use Drupal\field\Entity\FieldConfig;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\turnstile\TurnstileFieldManager;
+use Drupal\turnstile\TalerMerchantApiService;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -34,17 +35,29 @@ class TurnstileSettingsForm extends ConfigFormBase {
protected $fieldManager;
/**
+ * The Taler Merchant API service.
+ *
+ * @var \Drupal\turnstile\TalerMerchantApiService
+ */
+ protected $apiService;
+
+ /**
* Constructs a TurnstileSettingsForm object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The factory for configuration objects.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
+ * @param \Drupal\turnstile\TurnstileFieldManager $field_manager
+ * The field manager.
+ * @param \Drupal\turnstile\TalerMerchantApiService $api_service
+ * The API service.
*/
- public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, TurnstileFieldManager $field_manager) {
+ public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, TurnstileFieldManager $field_manager, TalerMerchantApiService $api_service) {
parent::__construct($config_factory);
$this->entityTypeManager = $entity_type_manager;
$this->fieldManager = $field_manager;
+ $this->apiService = $api_service;
}
/**
@@ -54,7 +67,8 @@ class TurnstileSettingsForm extends ConfigFormBase {
return new static(
$container->get('config.factory'),
$container->get('entity_type.manager'),
- $container->get('turnstile.field_manager')
+ $container->get('turnstile.field_manager'),
+ $container->get('turnstile.api_service')
);
}
@@ -116,15 +130,87 @@ class TurnstileSettingsForm extends ConfigFormBase {
'#default_value' => $config->get('grant_access_on_error') ?: '',
];
+ // Get subscriptions and currencies from API.
+ $subscriptions = $this->apiService->getSubscriptions();
+ $currencies = $this->apiService->getCurrencies();
+
+ if (empty($subscriptions) || empty($currencies)) {
+ $this->messenger()->addWarning($this->t('Unable to load subscriptions or currencies from API. Please check your configuration.'));
+ }
+
+ $form['subscription_prices'] = [
+ '#type' => 'fieldset',
+ '#title' => $this->t('Subscription prices'),
+ '#description' => $this->t('Set the price for buying each subscription type in different currencies.'),
+ '#tree' => TRUE,
+ ];
+
+ $existing_prices = $config->get('subscription_prices') ?: [];
+
+ foreach ($subscriptions as $subscription) {
+ $subscription_id = $subscription['id'] ?? $subscription['name'];
+ $subscription_label = $subscription['label'] ?? $subscription['name'];
+
+ // Skip the %none% case as you can't buy "no subscription"
+ if ($subscription_id === '%none%') {
+ continue;
+ }
+
+ $form['subscription_prices'][$subscription_id] = [
+ '#type' => 'details',
+ '#title' => $subscription_label,
+ '#open' => FALSE,
+ ];
+
+ foreach ($currencies as $currency) {
+ $currency_code = $currency['code'] ?? $currency['name'];
+ $currency_label = $currency['label'] ?? $currency['code'];
+
+ $form['subscription_prices'][$subscription_id][$currency_code] = [
+ '#type' => 'number',
+ '#title' => $currency_label,
+ '#default_value' => $existing_prices[$subscription_id][$currency_code] ?? '',
+ '#min' => 0,
+ '#step' => $currency['step'] ?? 0.01,
+ '#size' => 20,
+ '#description' => $this->t('Leave empty to prevent buying the subscription with this currency.'),
+ ];
+ }
+ }
+
return parent::buildForm($form, $form_state);
}
+
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
parent::validateForm($form, $form_state);
+ // Validate subscription prices
+ $subscription_prices = $form_state->getValue('subscription_prices');
+ if (is_array($subscription_prices)) {
+ foreach ($subscription_prices as $subscription_id => $currencies) {
+ if (is_array($currencies)) {
+ foreach ($currencies as $currency_code => $price) {
+ // Skip empty values as they are allowed (treated as zero).
+ if ($price === '' || $price === NULL) {
+ continue;
+ }
+
+ // Validate that the price is a valid non-negative number.
+ if (!is_numeric($price) || $price < 0) {
+ $form_state->setErrorByName(
+ "subscription_prices[$subscription_id][$currency_code]",
+ $this->t('Subscription prices cannot be negative.')
+ );
+ }
+ }
+ }
+ }
+ }
+
// Test the access token and backend URL.
$payment_backend_url = $form_state->getValue('payment_backend_url');
$access_token = $form_state->getValue('access_token');
@@ -284,12 +370,14 @@ class TurnstileSettingsForm extends ConfigFormBase {
}
$grant_access_on_error = $form_state->getValue('grant_access_on_error');
+ $subscription_prices = $form_state->getValue('subscription_prices');
// Save configuration.
$config->set('enabled_content_types', $new_enabled_types);
$config->set('payment_backend_url', $payment_backend_url);
$config->set('access_token', $access_token);
$config->set('grant_access_on_error', $grant_access_on_error);
+ $config->set('subscription_prices', $subscription_prices);
$config->save();
parent::submitForm($form, $form_state);