Commit 2df938ce authored by Sergey Shadrin's avatar Sergey Shadrin

[#125555] [BE] Модуль контроля лицензий

parent 0cfbe7ac
<?php
namespace Drupal\support_dar\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\support_dar\LicenseManager;
/**
* Configuration form.
*/
class SettingsForm extends ConfigFormBase {
/**
* Config key to save settings.
*/
public const CONFIG_KEY = 'support_dar.settings';
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [self::CONFIG_KEY];
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'support_dar_settings_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['site_key'] = [
'#type' => 'markup',
'#markup' => $this->t('Your site key: @key, give it to us to register your domain', ['@key' => LicenseManager::getSiteKey()]),
];
$config = $this->config(self::CONFIG_KEY);
$form['lms_site_url'] = [
'#type' => 'url',
'#title' => $this->t('License Manager System site url'),
'#default_value' => $config->get('lms_site_url'),
];
$form['lms_api_token'] = [
'#type' => 'textfield',
'#title' => $this->t('License Manager System API token'),
'#default_value' => $config->get('lms_api_token'),
'#maxlength' => 1024,
];
$form['lms_license_id'] = [
'#type' => 'textfield',
'#title' => $this->t('License ID in Manager System'),
'#default_value' => $config->get('lms_license_id'),
];
return parent::buildForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$this->config(self::CONFIG_KEY)
->set('lms_site_url', $form_state->getValue('lms_site_url'))
->set('lms_api_token', $form_state->getValue('lms_api_token'))
->set('lms_license_id', $form_state->getValue('lms_license_id'))
->save();
parent::submitForm($form, $form_state);
}
}
<?php
namespace Drupal\support_dar;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\State\StateInterface;
use Drupal\Core\Utility\Error;
use Drupal\support_dar\Form\SettingsForm;
use GuzzleHttp\ClientInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
/**
* DAR License Manager service.
*/
class LicenseManager {
// Initial status, in license manager system even doesn't contain record.
public const IS_NOT_ACTIVE = 0;
// Active license, and will be active long enough.
public const IS_ACTIVE = 1;
// Means license is active, but soon will be expired.
public const IS_SOON_EXPIRED = 2;
// Means config on drupal site not filled, and we cannot get data.
public const IS_NOT_CONFIGURED = 3;
// If expire time less than it means expiration is soon.
public const SOON_EXPIRED_TIME = 60 * 60 * 24 * 30;
public const EXPIRATION_DATE_KEY = 'dar_license.expiration';
public const LICENSE_STATUS_STATE_KEY = 'dar_license.license_status';
/**
* @todo replace on prod url.
*
* Url of license manager service.
*
* @var string
*/
private string $url = 'host.docker.internal:8001';
/**
* Prefix to concatenate on every request.
*
* @var string
*/
private string $api_prefix = '/api/v1';
/**
* Class constructor with all needed services.
*/
public function __construct(
protected ClientInterface $httpClient,
protected TimeInterface $time,
protected LoggerInterface $logger,
protected StateInterface $state,
protected CacheBackendInterface $cache,
protected ConfigFactoryInterface $configFactory,
) {
}
/**
* Get saved status.
*
* @return int
*/
public function getStatus(): int {
return $this->state->get(self::LICENSE_STATUS_STATE_KEY, self::IS_NOT_ACTIVE);
}
/**
* Generates site key.
*
* @return string
* Returns site key for license manager.
*/
public static function getSiteKey(): string {
global $base_url;
static $site_key;
if (!$site_key) {
$site_key = Crypt::hmacBase64($base_url, \Drupal::service('private_key')->get());
}
return $site_key;
}
/**
* Expiration date timestamp.
*
* @return int
* Returns timestamp or 0 if we couldn't get info.
*/
public function getExpirationDate(): int {
return $this->state->get(self::EXPIRATION_DATE_KEY);
}
/**
* Main method with all requests to check status, create license, etc.
*/
public function checkLicense(): int {
// Interval per day.
$interval = 60 * 60 * 24 * 1;
$last_check = $this->cache->get('dar_license.last_check');
$last_check = $last_check ? $last_check->data : 0;
$request_time = $this->time->getRequestTime();
if (($request_time - $last_check) > $interval) {
$config_data = $this->getConfigData();
if (empty($config_data['url']) || empty($config_data['api_token']) || empty($config_data['license_id'])) {
$this->state->set(self::LICENSE_STATUS_STATE_KEY, self::IS_NOT_CONFIGURED);
return self::IS_NOT_CONFIGURED;
}
$license_info = $this->getLicenseData();
$expiration_date = !empty($license_info['expiration_date']['date'])
? strtotime($license_info['expiration_date']['date'])
: 0;
$this->state->set(self::EXPIRATION_DATE_KEY, $expiration_date);
// First check that site key is registered in License Manager System.
if ($license_info['product_key'] === self::getSiteKey()) {
if (!$expiration_date || $expiration_date <= $request_time) {
$this->state->set(self::LICENSE_STATUS_STATE_KEY, self::IS_NOT_ACTIVE);
}
elseif ($expiration_date - $request_time > self::SOON_EXPIRED_TIME) {
$this->state->set(self::LICENSE_STATUS_STATE_KEY, self::IS_ACTIVE);
}
else {
$this->state->set(self::LICENSE_STATUS_STATE_KEY, self::IS_SOON_EXPIRED);
}
}
else {
$this->state->set(self::LICENSE_STATUS_STATE_KEY, self::IS_NOT_ACTIVE);
}
}
$this->cache->set('dar_license.last_check', $request_time);
return $this->state->get(self::LICENSE_STATUS_STATE_KEY, self::IS_NOT_ACTIVE);
}
/**
* Get config data.
*
* @param string $key
* Config value key.
*
* @return mixed
* Returns all settings from config or value from key.
*/
protected function getConfigData(string $key = ''): mixed {
static $data;
if (!isset($data)) {
$data = [];
$config = $this->configFactory->get(SettingsForm::CONFIG_KEY);
$data['url'] = $config->get('lms_site_url');
$data['api_token'] = $config->get('lms_api_token');
$data['license_id'] = $config->get('lms_license_id');
}
return $key ? $data[$key] : $data;
}
/**
* Check if license active or not.
*
* @return bool
*/
protected function getLicenseData(): array {
try {
$response = $this->makeRequest('GET', '/licenses/' . $this->getConfigData('license_id'));
$result = $response->getBody()->getContents();
return Json::decode($result);
}
catch (\Exception $e) {
Error::logException($this->logger, $e);
return [];
}
}
/**
* Base method to make request.
*
* @param string $method
* @param string $path
* API endpoint path.
*
* @return \Psr\Http\Message\ResponseInterface
* Response object.
*
* @throws \GuzzleHttp\Exception\GuzzleException
*/
protected function makeRequest(
string $method,
string $path,
array $body = [],
): ResponseInterface {
$response = $this->httpClient->request($method, $this->url . $this->api_prefix . $path, [
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $this->getConfigData('api_token'),
],
'body' => $body ? Json::encode($body) : '',
]);
return $response;
}
}
name: Support DAR
description: Provides integration with DAR Licence Manager System
package: DAR
type: module
core_version_requirement: ^10 || ^11
configure: support_dar.settings
'interface translation project': support_dar
'interface translation server pattern': modules/custom/support_dar/translations/support_dar.ru.po
support_dar.settings:
title: Support DAR settings
route_name: support_dar.settings
parent: system.admin_config_system
<?php
/**
* @file
* Main module file.
*/
use Drupal\Core\Link;
use Drupal\support_dar\LicenseManager;
/**
* Implements hook_cron().
*/
function support_dar_cron() {
/** @var \Drupal\support_dar\LicenseManager $license_manager */
$license_manager = \Drupal::service('support_dar.license_manager');
$license_manager->checkLicense();
}
/**
* Implements hook_requirements_alter().
*/
function support_dar_requirements_alter(array &$requirements) {
/** @var \Drupal\support_dar\LicenseManager $license_manager */
$license_manager = \Drupal::service('support_dar.license_manager');
$status = $license_manager->getStatus();
/** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
$date_formatter = \Drupal::service('date.formatter');
$expiration_date = $license_manager->getExpirationDate();
$support_mail = 'support@dar.ru';
switch ($status) {
case LicenseManager::IS_NOT_ACTIVE:
$severity = REQUIREMENT_ERROR;
$description = t('License not activated, contact us @support_mail', ['@support_mail' => $support_mail]);
break;
case LicenseManager::IS_ACTIVE:
// Everything is good, do nothing.
$description = t('Your license is active until @date', ['@date' => $date_formatter->format($expiration_date, 'html_date')]);
$severity = REQUIREMENT_OK;
break;
case LicenseManager::IS_SOON_EXPIRED:
$description = t('Your license is about to expire @data, please contact us to renew it @support_mail', [
'@date' => $date_formatter->format($expiration_date, 'html_date'),
'@support_mail' => $support_mail,
]);
$severity = REQUIREMENT_WARNING;
break;
case LicenseManager::IS_NOT_CONFIGURED:
$description = t('The license cannot be verified, the settings are not filled in. You can configure it @here',
[
'@here' => Link::createFromRoute(t('here'), 'support_dar.settings')
->toString(),
],
);
$severity = REQUIREMENT_WARNING;
break;
}
$requirements['support_dar'] = [
'title' => t('Support DAR'),
'description' => $description,
'severity' => $severity,
];
}
support_dar.settings:
path: '/admin/config/system/support-dar'
defaults:
_form: '\Drupal\support_dar\Form\SettingsForm'
_title: 'Support DAR settings'
requirements:
_permission: 'administer site configuration'
services:
support_dar.logger:
class: Drupal\Core\Logger\LoggerChannel
factory: logger.factory:get
arguments: [ 'support_dar' ]
support_dar.license_manager:
class: 'Drupal\support_dar\LicenseManager'
arguments:
- '@http_client'
- '@datetime.time'
- '@support_dar.logger'
- '@state'
- '@cache.default'
- '@config.factory'
msgid ""
msgstr ""
"Project-Id-Version: Support DAR\n"
"POT-Creation-Date: 2024-10-10 09:50+0200\n"
"PO-Revision-Date: 2024-10-10 09:50+0200\n"
"Language-Team: DAR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=((((n%10)==1)&&((n%100)!=11))?(0):(((((n%10)>=2)&&((n%10)<=4))&&(((n%100)<10)||((n%100)>=20)))?(1):2));\n"
msgid "Support DAR"
msgstr "Поддержка ДАР"
msgid "Support DAR settings"
msgstr "Настройки поддержки ДАР"
msgid "Provides integration with DAR Licence Manager System"
msgstr "Предоставляет интеграцию с системой контроля лицензий ДАР"
msgid "The license cannot be verified, the settings are not filled in. You can configure it @here"
msgstr "Лицензия не может быть проверена, настройки не заполнены. Вы можете сконфигурировать их @here"
msgid "License Manager System site url"
msgstr "URL-адрес сайта менеджера лицензий"
msgid "License Manager System API token"
msgstr "API токен менеджера лицензий"
msgid "ID in the License Manager System"
msgstr "Идентификатор в менеджере лицензий"
msgid "Your site key: @key, give it to us to register your domain"
msgstr "Ключ вашего сайта: @key, предоставьте его нам для регистрации вашего домена"
msgid "Your license is about to expire @data, please contact us to renew it @support_mail"
msgstr "Срок действия вашей лицензии истекает @data, чтобы продлить ее свяжитесь с нами @support_mail"
msgid "Your license is active until @date"
msgstr "Ваша лицензия активна до @date"
msgid "The license cannot be verified, the settings are not filled in. You can configure it @here"
msgstr "Лицензия не может быть подтверждена, настройки не заполнены. Вы можете настроить ее @here"
msgid "here"
msgstr "здесь"
msgid "License not activated, contact us @support_mail"
msgstr "Лицензия не активирована, свяжитесь с нами @support_mail"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment