full working version

This commit is contained in:
rnsrk 2023-11-15 01:53:03 +01:00
parent 2178db78f5
commit 308e21941a
22 changed files with 1434 additions and 366 deletions

View file

@ -0,0 +1,36 @@
<?php
namespace Drupal\wisski_cloud_account_manager\Access;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Database\Connection;
class AccountRouteAccessCheck implements AccessInterface {
protected $currentUser;
protected $database;
public function __construct(AccountInterface $currentUser, Connection $database) {
$this->currentUser = $currentUser;
$this->database = $database;
}
public function access($aid) {
// If the user has the "Administer WissKI Cloud Account Manager" role, allow access.
if ($this->currentUser->hasPermission('Administer WissKI Cloud Account Manager')) {
return AccessResult::allowed()->cachePerUser();
}
// Otherwise, check if the aid matches the user's aid in the database.
$uid = $this->currentUser->id();
$query = $this->database->select('wisski_cloud_account_manager_accounts', 'w')
->fields('w', ['aid'])
->condition('uid', $uid)
->condition('aid', $aid)
->execute();
$result = $query->fetchField();
return AccessResult::allowedIf($result)->cachePerUser();
}
}

View file

@ -5,6 +5,7 @@ namespace Drupal\wisski_cloud_account_manager\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
/**
* The Wisski Cloud account manager info controller.
@ -39,6 +40,63 @@ class WisskiCloudAccountManagerController extends ControllerBase {
);
}
/**
* Page list the account statuses.
*
* @return array
* The page build array.
*/
public function accountManagingPage(): array {
$currentUser = \Drupal::currentUser();
$healthCheck = $this->wisskiCloudAccountManagerDaemonApiActions->healthCheck();
$accounts = $this->wisskiCloudAccountManagerDaemonApiActions->getAccounts();
// If the user is not an admin, filter the accounts to only include their own.
if (!$currentUser->hasPermission('admister wisski cloud account manager')) {
$accounts = array_filter($accounts, function($account) use ($currentUser) {
return $account['uid'] === $currentUser->id();
});
}
return [
'#theme' => 'wisski_cloud_account_manager_account_managing_page',
'#accounts' => $accounts,
'#healthCheck' => $healthCheck,
'#attached' => [
'library' => [
'wisski_cloud_account_manager/accountOptions',
'wisski_cloud_account_manager/globalStyling',
'wisski_cloud_account_manager/provisionStatus'
],
],
'#cache' => [
'max-age' => 0,
],
];
}
// @todo Implement healthcheckPage().
public function healthcheckPage(): array {
return [
'#theme' => 'wisski_cloud_account_manager_healthcheck_page',
'#healthCheck' => $this->wisskiCloudAccountManagerDaemonApiActions->healthCheck(),
];
}
public function provisionStatusPage($aid) {
$accounts = $this->wisskiCloudAccountManagerDaemonApiActions->getAccounts($aid);
// Return the status as a JSON response.
switch ($accounts[0]['provisioned']) {
case '0':
return new JsonResponse(['status' => 'no']);
case '1':
return new JsonResponse(['status' => 'ongoing']);
case '2':
return new JsonResponse(['status' => 'yes']);
case '3':
return new JsonResponse(['status' => 'unknown']);
}
return new JsonResponse(['status' => $accounts[0]['provisioned']]);
}
/**
* Info page for terms and conditions.
*
@ -63,41 +121,13 @@ class WisskiCloudAccountManagerController extends ControllerBase {
* The page build array.
*/
public function validationPage(string $validationCode): array {
$account = $this->wisskiCloudAccountManagerDaemonApiActions->validateAccount($validationCode);
$user = $this->wisskiCloudAccountManagerDaemonApiActions->validateAccount($validationCode);
return [
'#theme' => 'wisski_cloud_account_manager_validation_page',
'#account' => $account,
'#attached' => [
'library' => [
'wisski_cloud_account_manager/wisski_cloud_account_manager',
],
],
'#cache' => [
'max-age' => 0,
],
'#markup' => $this->t('Your WissKI Cloud account for user :name is now validated. You can now <a href="/user">login</a> and start a provision!.', [
':name' => $user['name'],
]),
];
}
/**
* Page list the account statuses.
*
* @return array
* The page build array.
*/
public function accountManagingPage(): array {
$accounts = $this->wisskiCloudAccountManagerDaemonApiActions->getAccounts();
return [
'#theme' => 'wisski_cloud_account_manager_account_managing_page',
'#accounts' => $accounts,
'#attached' => [
'library' => [
'wisski_cloud_account_manager/wisski_cloud_account_manager',
],
],
'#cache' => [
'max-age' => 0,
],
];
}
}

View file

@ -16,9 +16,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
*/
class WisskiCloudAccountManagerCreateForm extends FormBase {
/**
* The config factory service.
*
@ -126,7 +123,7 @@ class WisskiCloudAccountManagerCreateForm extends FormBase {
'#type' => 'textfield',
'#title' => $this->t('Username'),
'#maxlength' => 20,
'#description' => $this->t('WissKI cloud login user. Only small caps (a-z), underscore (_), minus (-) and 20 letter maximum allowed, i.e. "wisski_user".'),
'#description' => $this->t('WissKI cloud login - NOT your password for your instance - this will be send separately. Only small caps (a-z), underscore (_), minus (-) and 20 letter maximum allowed, i.e. "wisski_user".'),
'#pattern' => '[a-z]+([_-]{1}[a-z]+)*',
'#required' => TRUE,
];
@ -175,38 +172,54 @@ class WisskiCloudAccountManagerCreateForm extends FormBase {
$dataToCheck['email'] = $form_state->getValue('email');
$dataToCheck['emailProvider'] = explode('@', $dataToCheck['email'])[1];
$dataToCheck['subdomain'] = $form_state->getValue('subdomain');
$dataToCheck['usernameBlacklist'] = $this->settings->get('usernameBlacklist') ?? '';
$dataToCheck['emailProviderBlacklist'] = $this->settings->get('emailProviderBlacklist') ?? '';
$dataToCheck['subdomainBlacklist'] = $this->settings->get('subdomainBlacklist') ?? '';
$response = $this->wisskiCloudAccountManagerDaemonApiActions->checkAccountData($dataToCheck);
// Check if username is too short.
if (strlen($dataToCheck['username']) < 2) {
$form_state->setErrorByName('username', $this->t('The username "@username" is too short, please use at least 2 characters.', ['@username' => $dataToCheck['username']]));
}
if (!$response['success']) {
$this->messenger->addError('Can not communicate with the provision daemon, please try again later or write an email to cloud@wiss-ki.eu.');
}
if (strlen($dataToCheck['username']) < 3) {
$form_state->setErrorByName('username', $this->t('The username "@username" is too short, please use at least 3 characters.', ['@username' => $dataToCheck['username']]));
}
if (in_array($dataToCheck['username'], preg_split('/\r\n|\r|\n/', $this->settings->get('usernameBlacklist')))) {
// Check if username is in blacklist.
if (in_array($dataToCheck['username'], preg_split('/\r\n|\r|\n/', $dataToCheck['usernameBlacklist']))) {
$form_state->setErrorByName('username', $this->t('The username "@username" is not allowed.', ['@username' => $dataToCheck['username']]));
}
if ($response['accountData']['accountWithUsername']) {
$form_state->setErrorByName('username', $this->t('The username "@username" is already in use.', ['@username' => $dataToCheck['username']]));
// Check if username only contains lowercase letters, numbers, and underscores
if (!preg_match('/^[a-z0-9_]+$/', $dataToCheck['username'])) {
$form_state->setErrorByName('username', t('Username can only contain lowercase letters, numbers, and underscores.'));
}
if (in_array($dataToCheck['emailProvider'], preg_split('/\r\n|\r|\n/', $this->settings->get('emailProviderBlacklist')))) {
// Check if username is unique
$userFromUsername = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties(['name' =>$dataToCheck['username']]);
if (!empty($userFromUsername)) {
$form_state->setErrorByName('username', $this->t('The username is already taken.'));
}
// Check if email provider is in blacklist.
if (in_array($dataToCheck['emailProvider'], preg_split('/\r\n|\r|\n/', $dataToCheck['emailProviderBlacklist']))) {
$form_state->setErrorByName('email', $this->t('The email provider "@provider"is not allowed.', ['@provider' => $dataToCheck['emailProvider']]));
}
if ($response['accountData']['accountWithEmail']) {
// Check if email is already in use.
$userFromEmail = \Drupal::entityTypeManager()->getStorage('user')->loadByProperties(['name' => $dataToCheck['email']]);
if (!empty($userFromEmail)) {
$form_state->setErrorByName('email', $this->t('The email "@email" is already in use.', ['@email' => $dataToCheck['email']]));
}
// Check if subdomain is too short.
if (strlen($dataToCheck['subdomain']) < 3) {
$form_state->setErrorByName('subdomain', $this->t('The subdomain "@subdomain" is too short, please use at least 3 characters.', ['@subdomain' => $dataToCheck['subdomain']]));
}
if (in_array($dataToCheck['subdomain'], preg_split('/\r\n|\r|\n/', $this->settings->get('subdomainBlacklist')))) {
// Check if subdomain is in blacklist.
if (in_array($dataToCheck['subdomain'], preg_split('/\r\n|\r|\n/', $dataToCheck['emailProviderBlacklist']))) {
$form_state->setErrorByName('subdomain', $this->t('The subdomain "@subdomain" is not allowed.', ['@subdomain' => $dataToCheck['subdomain']]));
}
if ($response['accountData']['accountWithSubdomain']) {
// Check if subdomain is already in use.
if ($this->wisskiCloudAccountManagerDaemonApiActions->checkForRedundantAccountData('subdomain', $dataToCheck['subdomain'])) {
$form_state->setErrorByName('subdomain', $this->t('The subdomain "@subdomain" is already in use.', ['@subdomain' => $dataToCheck['subdomain']]));
}
@ -230,11 +243,8 @@ class WisskiCloudAccountManagerCreateForm extends FormBase {
$account["password"] = $field['password'];
$account["subdomain"] = $field['subdomain'];
$accountResponse = $this->wisskiCloudAccountManagerDaemonApiActions->addAccount($account);
if (!$accountResponse['success']) {
throw new Exception('Get no valid response from api daemon. Can not send validiation email.');
};
$this->wisskiCloudAccountManagerDaemonApiActions->sendValidationEmail($accountResponse['data']['email'], $accountResponse['data']['validationCode']);
$user = $this->wisskiCloudAccountManagerDaemonApiActions->addAccount($account);
$this->wisskiCloudAccountManagerDaemonApiActions->sendValidationEmail($user['email'], $user['personName'], $user['validationCode']);
$this->messenger()
->addMessage($this->t('The account data has been successfully saved, please check your email for validation!'));

View file

@ -0,0 +1,111 @@
<?php
namespace Drupal\wisski_cloud_account_manager\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions;
use Drupal\Core\Url;
class WisskiCloudAccountManagerDeleteForm extends ConfirmFormBase {
/**
* @var array
* The account.
*/
protected array $account;
/**
* @var \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions
* The WissKi Cloud account manager daemon API actions service.
*/
protected WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions;
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'wisski_cloud_account_manager_delete_form';
}
/**
* Class constructor.
*
* @param \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions
* The WissKi Cloud account manager daemon API actions service.
*/
public function __construct(WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions) {
$this->wisskiCloudAccountManagerDaemonApiActions = $wisskiCloudAccountManagerDaemonApiActions;
$aid = \Drupal::routeMatch()->getParameter('aid');
$this->account = $this->wisskiCloudAccountManagerDaemonApiActions->getAccounts($aid)[0];
}
/**
* Populate the reachable variables from services.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The class container.
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('wisski_cloud_account_manager.daemon_api.actions'),
);
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Do you really want to delete your WissKI Cloud Instance?');
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return Url::fromRoute('wisski_cloud_account_manager.validate')
->setRouteParameter('validationCode', $this->account['validation_code']);
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('This will delete your WissKI Cloud instance. This action cannot be undone. Your Drupal user and WissKI Cloud account will remain.');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Delete');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
$form['account_table'] = [
'#type' => 'table',
'#rows' => [
[$this->t('Subdomain'), $this->account['subdomain']],
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$aid = \Drupal::routeMatch()->getParameter('aid');
$this->wisskiCloudAccountManagerDaemonApiActions->crudInstance('delete', $aid);
$form_state->setRedirect('wisski_cloud_account_manager.manage');
}
}

View file

@ -0,0 +1,115 @@
<?php
namespace Drupal\wisski_cloud_account_manager\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions;
use Drupal\Core\Url;
class WisskiCloudAccountManagerProvisionForm extends ConfirmFormBase {
/**
* @var \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions
* The WissKi Cloud account manager daemon API actions service.
*/
protected WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions;
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'wisski_cloud_account_manager_provision_form';
}
/**
* Class constructor.
*
* @param \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions
* The WissKi Cloud account manager daemon API actions service.
*/
public function __construct(WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions) {
$this->wisskiCloudAccountManagerDaemonApiActions = $wisskiCloudAccountManagerDaemonApiActions;
}
/**
* Populate the reachable variables from services.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The class container.
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('wisski_cloud_account_manager.daemon_api.actions'),
);
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Do you really want to start WissKI Cloud provision?');
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return Url::fromRoute('wisski_cloud_account_manager.settings');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('This will start a WissKI Cloud account provision.');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Provise a WissKI Cloud account');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
$aid = \Drupal::routeMatch()->getParameter('aid');
$account = $this->wisskiCloudAccountManagerDaemonApiActions->getAccounts($aid)[0];
$form['info'] = [
'#type' => 'table',
'#header' => [
$this->t('Account id'),
$this->t('Account name'),
$this->t('Account email'),
$this->t('Domain'),
],
'#rows' => [
[
$account['aid'],
$account['name'],
$account['mail'],
$account['subdomain'] . '.wisski.cloud',
],
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$aid = \Drupal::routeMatch()->getParameter('aid');
$result = $this->wisskiCloudAccountManagerDaemonApiActions->crudInstance('create', $aid);
$form_state->setRedirect('wisski_cloud_account_manager.manage');
}
}

View file

@ -0,0 +1,105 @@
<?php
namespace Drupal\wisski_cloud_account_manager\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions;
use Drupal\Core\Url;
class WisskiCloudAccountManagerPurgeForm extends ConfirmFormBase {
/**
* @var \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions
* The WissKi Cloud account manager daemon API actions service.
*/
protected WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions;
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'wisski_cloud_account_manager_purge_form';
}
/**
* Class constructor.
*
* @param \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions
* The WissKi Cloud account manager daemon API actions service.
*/
public function __construct(WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions) {
$this->wisskiCloudAccountManagerDaemonApiActions = $wisskiCloudAccountManagerDaemonApiActions;
}
/**
* Populate the reachable variables from services.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The class container.
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('wisski_cloud_account_manager.daemon_api.actions'),
);
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Do you really want to purge your WissKI Cloud account?');
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return Url::fromRoute('wisski_cloud_account_manager.settings');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('This will delete your WissKI Cloud account, your Drupal user, your WissKI Cloud instance and all data associated with it. This action cannot be undone.');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Purge');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
$aid = \Drupal::routeMatch()->getParameter('aid');
$account = $this->wisskiCloudAccountManagerDaemonApiActions->getAccounts($aid)[0];
$form['account_table'] = [
'#type' => 'table',
'#rows' => [
[$this->t('Subdomain'), $account['subdomain']],
[$this->t('Account name'), $account['name'] ?: $this->t('Seems that Drupal user has already been deleted, delete the remaining account data and instance.')],
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$aid = \Drupal::routeMatch()->getParameter('aid');
$this->wisskiCloudAccountManagerDaemonApiActions->purgeAccount($aid);
$form_state->setRedirect('wisski_cloud_account_manager.manage');
}
}

View file

@ -42,32 +42,39 @@ class WisskiCloudAccountManagerSettingsForm extends ConfigFormBase {
'#default_value' => $config->get('daemonUrl'),
];
$form['allAccounts'] = [
$form['wsUrl'] = [
'#type' => 'textfield',
'#title' => $this->t('All accounts URL path'),
'#description' => $this->t('Provide the endpoint to the GET endpoint for all accounts, i. e. "/account/all"'),
'#default_value' => $config->get('allAccounts'),
'#title' => $this->t('The websocket URL of the WissKI Cloud'),
'#description' => $this->t('Provide the complete base URL with protocol, domain (resp. service name in docker), ports and API path, i. e. "wss://panel.wisski.cloud/api/v1/ws"'),
'#default_value' => $config->get('wsUrl'),
];
$form['accountPostUrlPath'] = [
'#type' => 'textfield',
'#title' => $this->t('POST URL path'),
'#description' => $this->t('Provide the path to the POST endpoint, i. e. "/account"'),
'#default_value' => $config->get('accountPostUrlPath'),
$form['wsToken'] = [
'#type' => 'password',
'#title' => $this->t('The websocket access token of the WissKI Cloud provisioning account.'),
'#description' => $this->t('Provide the access token for the websocket, i. e. "1234567890"'),
'#default_value' => $config->get('wsToken'),
];
$form['accountFilterByData'] = [
$form['provisionRoute'] = [
'#type' => 'textfield',
'#title' => $this->t('Filter by Data URL path'),
'#description' => $this->t('Provide the path to the Get account by data endpoint, i. e. "/account/by_data"'),
'#default_value' => $config->get('accountFilterByData'),
'#title' => $this->t('Instance provision URL path'),
'#description' => $this->t('Provide the path to the account validation PUT endpoint, i. e. "/provision"'),
'#default_value' => $config->get('provisionRoute'),
];
$form['accountValidation'] = [
$form['deleteRoute'] = [
'#type' => 'textfield',
'#title' => $this->t('User Validation URL path'),
'#description' => $this->t('Provide the path to the account validation PUT endpoint, i. e. "/account/validation"'),
'#default_value' => $config->get('accountValidation'),
'#title' => $this->t('Instance delete URL path'),
'#description' => $this->t('Provide the path to the account validation DELETE endpoint, i. e. "/delete"'),
'#default_value' => $config->get('deleteRoute'),
];
$form['healthCheckRoute'] = [
'#type' => 'textfield',
'#title' => $this->t('Deamon health check URL path'),
'#description' => $this->t('Provide the path to the health check GET endpoint, i. e. "/health-check"'),
'#default_value' => $config->get('healthCheckRoute'),
];
$form['usernameBlacklist'] = [
@ -121,15 +128,16 @@ class WisskiCloudAccountManagerSettingsForm extends ConfigFormBase {
public function submitForm(array &$form, FormStateInterface $form_state) {
$config = $this->config('wisski_cloud_account_manager.settings');
$config->set('daemonUrl', $form_state->getValue('daemonUrl'))
->set('accountPostUrlPath', $form_state->getValue('accountPostUrlPath'))
->set('allAccounts', $form_state->getValue('allAccounts'))
->set('accountFilterByData', $form_state->getValue('accountFilterByData'))
->set('accountProvisionAndValidationCheck', $form_state->getValue('accountProvisionAndValidationCheck'))
->set('accountValidation', $form_state->getValue('accountValidation'))
->set('usernameBlacklist', $form_state->getValue('usernameBlacklist'))
$config
->set('daemonUrl', $form_state->getValue('daemonUrl'))
->set('deleteRoute', $form_state->getValue('deleteRoute'))
->set('emailProviderBlacklist', $form_state->getValue('emailProviderBlacklist'))
->set('healthCheckRoute', $form_state->getValue('healthCheckRoute'))
->set('provisionRoute', $form_state->getValue('provisionRoute'))
->set('usernameBlacklist', $form_state->getValue('usernameBlacklist'))
->set('subdomainBlacklist', $form_state->getValue('subdomainBlacklist'))
->set('wsUrl', $form_state->getValue('wsUrl'))
->set('wsToken', $form_state->getValue('wsToken'))
->save();
parent::submitForm($form, $form_state);

View file

@ -0,0 +1,113 @@
<?php
namespace Drupal\wisski_cloud_account_manager\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions;
use Drupal\Core\Url;
class WisskiCloudAccountManagerValidationForm extends ConfirmFormBase {
/**
* @var \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions
* The WissKi Cloud account manager daemon API actions service.
*/
protected WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions;
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'wisski_cloud_account_manager_validation_form';
}
/**
* Class constructor.
*
* @param \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions
* The WissKi Cloud account manager daemon API actions service.
*/
public function __construct(WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions) {
$this->wisskiCloudAccountManagerDaemonApiActions = $wisskiCloudAccountManagerDaemonApiActions;
}
/**
* Populate the reachable variables from services.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The class container.
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('wisski_cloud_account_manager.daemon_api.actions'),
);
}
/**
* {@inheritdoc}
*/
public function getQuestion() {
return $this->t('Do you really want to start WissKI Cloud validation?');
}
/**
* {@inheritdoc}
*/
public function getCancelUrl() {
return Url::fromRoute('wisski_cloud_account_manager.settings');
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('This will start a WissKI Cloud account validation.');
}
/**
* {@inheritdoc}
*/
public function getConfirmText() {
return $this->t('Validate a WissKI Cloud account');
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
$aid = \Drupal::routeMatch()->getParameter('aid');
$account = $this->wisskiCloudAccountManagerDaemonApiActions->getAccounts($aid)[0];
$form['info'] = [
'#type' => 'table',
'#header' => [
$this->t('Account id'),
$this->t('Account name'),
$this->t('Account email'),
$this->t('Domain'),
],
'#rows' => [
[
$account['aid'],
$account['name'],
$account['mail'],
$account['subdomain'] . '.wisski.cloud',
],
],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$aid = \Drupal::routeMatch()->getParameter('aid');
$this->wisskiCloudAccountManagerDaemonApiActions->validateAccount($aid);
$form_state->setRedirect('wisski_cloud_account_manager.manage');
}
}

View file

@ -5,13 +5,17 @@ namespace Drupal\wisski_cloud_account_manager;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\Schema\Undefined;
use Drupal\Core\Database\Connection;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Mail\MailManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Template\TwigEnvironment;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\user\Entity\User;
use GuzzleHttp\ClientInterface;
/**
@ -22,32 +26,19 @@ class WisskiCloudAccountManagerDaemonApiActions {
use DependencySerializationTrait;
/**
* The URL path to all account data GET endpoint.
* The admin email address.
*
* @var string
*/
private string $ALL_ACCOUNTS = '/account/all';
private string $ADMIN_EMAIL;
/**
* The URL path to the POST endpoint.
* The URL path to provision PUT endpoint.
*
* @var string
*/
private string $ACCOUNT_POST_URL_PART = '/account';
private string $PROVISION_ROUTE;
/**
* The URL path to provision and validation GET endpoint.
*
* @var string
*/
private string $ACCOUNT_PROVISION_AND_VALIDATION_URL_PART;
/**
* The URL path to provision and validation GET endpoint.
*
* @var string
*/
private string $ACCOUNT_VALIDATION_URL_PART = '/account/validation';
/**
* The base URL of the WissKI Cloud account manager daemon.
@ -57,18 +48,34 @@ class WisskiCloudAccountManagerDaemonApiActions {
private string $DAEMON_URL;
/**
* The URL path to the filter by account data GET endpoint.
* The URL path to delete DELETE endpoint.
*
* @var string
*/
private string $FILTER_BY_DATA_URL_PART = '/account/by_data';
private string $DELETE_ROUTE;
/**
* The settings config.
* The database.
*
* @var \Drupal\Core\Config\Config
* @var \Drupal\Core\Database\Connection
*/
protected Config $settings;
protected Connection $database;
/**
* The Route to the health check GET endpoint.
*
* @var string
*/
private string $HEALTH_CHECK_ROUTE;
/**
* The Route to the info GET endpoint.
*
* @var string
* @todo not yet implemented
*/
private string $INFO_ROUTE = '/info';
/**
* The HTTP client.
@ -77,6 +84,13 @@ class WisskiCloudAccountManagerDaemonApiActions {
*/
protected ClientInterface $httpClient;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected LanguageManagerInterface $languageManager;
/**
* The logger factory.
*
@ -84,6 +98,13 @@ class WisskiCloudAccountManagerDaemonApiActions {
*/
protected LoggerChannelFactoryInterface $loggerFactory;
/**
* The mail manager.
*
* @var \Drupal\Core\Mail\MailManagerInterface
*/
protected MailManagerInterface $mailManager;
/**
* The messenger service.
*
@ -91,20 +112,6 @@ class WisskiCloudAccountManagerDaemonApiActions {
*/
protected MessengerInterface $messenger;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected LanguageManagerInterface $languageManager;
/**
* The mail manager.
*
* @var \Drupal\Core\Mail\MailManagerInterface
*/
protected MailManagerInterface $mailManager;
/**
* The request stack.
*
@ -112,6 +119,15 @@ class WisskiCloudAccountManagerDaemonApiActions {
*/
protected RequestStack $requestStack;
/**
* The settings config.
*
* @var \Drupal\Core\Config\Config
*/
protected Config $settings;
/**
* The string translation service.
*
@ -119,61 +135,212 @@ class WisskiCloudAccountManagerDaemonApiActions {
*/
protected TranslationInterface $stringTranslation;
/**
* The Twig renderer.
*
* @var \Drupal\Core\Template\TwigEnvironment
*/
protected TwigEnvironment $twig;
/**
* Class constructor.
*/
public function __construct(
ConfigFactoryInterface $configFactory,
Connection $database,
ClientInterface $httpClient,
LanguageManagerInterface $languageManager,
LoggerChannelFactoryInterface $loggerFactory,
MessengerInterface $messenger,
MailManagerInterface $mailManager,
MessengerInterface $messenger,
RequestStack $requestStack,
TranslationInterface $stringTranslation,
TwigEnvironment $twig
) {
// Services from container.
$settings = $configFactory
->getEditable('wisski_cloud_account_manager.settings');
->getEditable('wisski_cloud_account_manager.settings');
$this->httpClient = $httpClient;
$this->database = $database;
$this->languageManager = $languageManager;
$this->loggerFactory = $loggerFactory;
$this->mailManager = $mailManager;
$this->messenger = $messenger;
$this->requestStack = $requestStack;
$this->settings = $settings;
$this->stringTranslation = $stringTranslation;
$this->loggerFactory = $loggerFactory;
$this->messenger = $messenger;
$this->httpClient = $httpClient;
$this->mailManager = $mailManager;
$this->requestStack = $requestStack;
$this->languageManager = $languageManager;
$this->twig = $twig;
// Set the daemon URL and the URL parts class variables.
$this->DAEMON_URL = $settings->get('daemonUrl') ?: 'http://wisski_cloud_api_daemon:3000/wisski-cloud-daemon/api/v1';
$this->ALL_ACCOUNTS = $settings->get('allAccounts') ?: '/account/all';
$this->ACCOUNT_POST_URL_PART = $settings->get('accountPostUrlPath') ?: '/account';
$this->FILTER_BY_DATA_URL_PART = $settings->get('accountFilterByData') ?: '/account/by_data';
$this->ACCOUNT_PROVISION_AND_VALIDATION_URL_PART = $settings->get('accountProvisionAndValidationUrlPart') ?: '/account/provision_and_validation';
$this->ACCOUNT_VALIDATION_URL_PART = $settings->get('accountValidationUrlPart') ?: '/account/validation';
$this->DAEMON_URL = $settings->get('daemonUrl') ?: 'http://wisski_cloud_api_daemon_app:2912/wisski-cloud-daemon/api/v1';
$this->DELETE_ROUTE = $settings->get('deleteRoute') ?: '/delete';
$this->PROVISION_ROUTE = $settings->get('provisionRoute') ?: '/provision';
$this->ADMIN_EMAIL = \Drupal::config('system.site')->get('mail');
$this->HEALTH_CHECK_ROUTE= $settings->get('healthCheckRoute') ?: '/health-check';
}
/**
* Adds a new account to the WissKI Cloud account manager daemon.
* Adds a new account to the instance.
*
* First a new Drupal user is created. Additional data is
* stored in the wisski_cloud_account_manager_accounts table.
*
* @param array $account
* The account to add.
*
* @return array
* The response from the daemon (account id with validation code).
* The account id with validation code.
*/
public function addAccount(array $account): array {
try {
$request = [
'headers' => [
'Content-Type' => 'application/json',
],
'body' => json_encode($account),
// Get current language.
$language = $this->languageManager->getCurrentLanguage()->getId();
// Create Drupal user object.
$user = User::create();
// Mandatory.
$user->setPassword($account['password']);
$user->enforceIsNew();
$user->setEmail($account['email']);
$user->setUsername($account['username']); // This username must be unique and accepts only string. It must be a minimum of two characters and can contain only lowercase letters, numbers, and underscores.
// Optional.
$user->set('init', $account['email']);
$user->set('langcode', $language);
$user->set('preferred_langcode', $language);
$user->set('preferred_admin_langcode', $language);
// Save user.
$result = $user->save();
$validationCode = $this->generateValidationCode();
$database = $this->database;
// Check if a record with this user ID already exists.
$query = $database->select('wisski_cloud_account_manager_accounts', 'w')
->fields('w', ['uid'])
->condition('w.uid', $user->id(), '=');
$result = $query->execute()->fetchField();
if ($result) {
throw new \Exception('A record with this user ID already exists.');
}
$query = $database->insert('wisski_cloud_account_manager_accounts')
->fields([
'uid' => $user->id(),
'person_name' => $account['personName'],
'organisation' => $account['organisation'],
'subdomain' => $account['subdomain'],
'validation_code' => $validationCode,
]);
$query->execute();
return [
'userId' => $user->id(),
'username' => $account['username'],
'personName' => $account['personName'],
'email' => $account['email'],
'subdomain' => $account['subdomain'],
'validationCode' => $validationCode ,
];
$accountPostUrl = $this->DAEMON_URL . $this->ACCOUNT_POST_URL_PART;
$response = $this->httpClient->post($accountPostUrl, $request);
return json_decode($response->getBody()
->getContents(), TRUE);
}
catch (\Exception $e) {
// Request failed, handle the error.
$this->loggerFactory
->get('wisski_cloud_account_manager')
->error('Can not create account: ' . $e->getMessage());
$this->messenger
->addError($this->stringTranslation->translate('Error creating account. See logs for details.'));
return [];
}
}
/**
* Check for redundant account data.
*
* @param string $column
* The column to check.
* @param string $value
* The value to check.
*/
public function checkForRedundantAccountData(string $column, string $value) {
$database = \Drupal::database();
$query = $database->select('wisski_cloud_account_manager_accounts', 'w');
$query->fields('w', [$column]);
$query->condition('w.' . $column, $value, '=');
if ($query->execute()->fetchField()) {
return TRUE;
}
else {
return FALSE;
}
}
/**
* Provisions an account in the WissKI Cloud account manager daemon.
*
* @param string $action
* The action to perform: create, delete, get.
* @param int $aid
* The account ID to provision.
*
* @return array
* The response from the daemon.
*/
public function crudInstance($action, $aid) {
try {
$aid = trim($aid);
// Build the query string from the parameters.
$query_string = http_build_query([
'aid' => $aid,
]);
// Determine the route part depending on the action.
switch ($action) {
case 'create':
$restMethod = 'put';
$routePart = $this->PROVISION_ROUTE;
break;
case 'delete':
$restMethod = 'delete';
$routePart = $this->DELETE_ROUTE;
break;
default:
$restMethod = 'get';
$routePart = $this->INFO_ROUTE;
break;
}
// Combine the base URL and the query string.
$request_url = $this->DAEMON_URL . $routePart . '?' . $query_string;
// Send the GET request using the `drupal_http_request()` function.
$response = $this->httpClient->request($restMethod, $request_url);
// Check the response and handle the data accordingly.
if ($response->getStatusCode() == 200 || $response->getStatusCode() == 201) {
// Request successful, handle the data in $response->data.
$resultArray = json_decode($response->getBody()->getContents(), TRUE);
$this->messenger
->addMessage($this->stringTranslation->translate('@message', ['@message' => $resultArray['message']]));
return $resultArray;
}
if ($response->getStatusCode() == 404) {
// Request successful, handle the data in $response->data.
$resultArray = json_decode($response->getBody()->getContents(), TRUE);
$this->messenger
->addError($this->stringTranslation->translate('@message', ['@message' => $resultArray['message']]));
return $resultArray;
}
else {
// Request failed, handle the error.
return [
"message" => 'Request failed with code: ' . $response->getStatusCode(),
"data" => [],
'success' => FALSE,
'error' => $response->getBody()->getContents(),
];
}
}
catch (\Exception $e) {
// Request failed, handle the error.
@ -181,60 +348,130 @@ class WisskiCloudAccountManagerDaemonApiActions {
->get('wisski_cloud_account_manager')
->error('Request failed with exception: ' . $e->getMessage());
$this->messenger
->addError($this->stringTranslation->translate('Can not communicate with the WissKI Cloud account manager daemon. Try again later or contact cloud@wiss-ki.eu.'));
->addError($this->stringTranslation->translate('Can not communicate with the WissKI Cloud account manager daemon. Try again later or contact @email.',
['@email'
=> $this->ADMIN_EMAIL]));
return [
"message" => 'Request failed with exception: ' . $e->getMessage(),
"data" => [
'email' => NULL,
'validationCode' => NULL,
],
"message" => 'Request failed with exception.',
"data" => [],
'success' => FALSE,
'error' => $e->getMessage(),
];
}
}
}
/**
* Check if an account with the given data already exists.
* Deletes an account from the WissKI Cloud account manager daemon.
*
* @param array $dataToCheck
* The data to check. Possible keys are:
* - email
* - subdomain
* - username.
* @param int $uid
* The user ID of the account to delete.
*
* @return array
* The response from the daemon.
*/
public function checkAccountData(array $dataToCheck): array {
public function deleteAccount(int $aid): array {
try {
// Build the query string from the parameters.
$query_string = http_build_query($dataToCheck);
$database = $this->database;
// Select the user ID from the accounts table.
$selectQuery = $database->select('wisski_cloud_account_manager_accounts', 'w')
->fields('w', ['uid'])
->condition('w.aid', $aid, '=');
$uid = $selectQuery->execute()->fetchField();
// Delete the account from the accounts table.
$deleteQuery = $database->delete('wisski_cloud_account_manager_accounts')
->condition('aid', $aid, '=');
$deleteQuery->execute();
// Delete the user if exists.
$user = User::load($uid);
$user ? $user->delete() : NULL;
$this->messenger
->addMessage($this->stringTranslation->translate('Account deleted successfully.'));
return [
'message' => 'Account deleted successfully.',
'success' => TRUE,
];
}
catch (\Exception $e) {
// Request failed, handle the error.
$this->loggerFactory
->get('wisski_cloud_account_manager')
->error('Request failed with exception: ' . $e->getMessage());
$this->messenger
->addError($this->stringTranslation->translate('Something went wrong!' . $e->getMessage()));
}
}
/**
* Generates a random validation code with 32 characters.
*
* @return string
* The generated validation code.
*/
function generateValidationCode() {
// Generate 16 random bytes and convert them to a 32 characters hexadecimal string
$code = bin2hex(random_bytes(16));
return $code;
}
/**
* Query accounts from the WissKI Cloud account manager daemon.
*
* @param int $aid
* The account ID to query.
*
* @return array[aid, name, mail, organisation, person_name, provisioned, status, subdomain, uid, validation_code]
* The accounts response from the daemon.
*/
public function getAccounts($aid = null): array {
try {
$query = $this->database->select('wisski_cloud_account_manager_accounts', 'w');
$query->fields('w', ['aid', 'organisation', 'person_name', 'provisioned', 'subdomain', 'uid', 'validation_code']);
$query->leftjoin('users_field_data', 'u', 'w.uid = u.uid');
$query->fields('u', ['name', 'mail', 'status']);
if ($aid) {
$query->condition('w.aid', $aid, '=');
}
$accounts = $query->execute()->fetchAll(\PDO::FETCH_ASSOC);
return $accounts;
}
catch (\Exception $e) {
// Request failed, handle the error.
$this->loggerFactory
->get('wisski_cloud_account_manager')
->error('Request failed with exception: ' . $e->getMessage());
$this->messenger
->addError($this->stringTranslation->translate('Can not communicate with the WissKI Cloud account manager daemon. Try again later or contact cloud@wiss-ki.eu.'));
return [];
}
}
/**
* Checks if the WissKI Cloud account manager daemon is available.
*
* @return array[message:string, success:boolean]
*
*/
public function healthCheck() {
try {
// Combine the base URL and the query string.
$request_url = $this->DAEMON_URL . $this->FILTER_BY_DATA_URL_PART . '?' . $query_string;
$request_url = $this->DAEMON_URL . $this->HEALTH_CHECK_ROUTE;
// Send the GET request using the `drupal_http_request()` function.
$response = $this->httpClient->get($request_url);
$response = $this->httpClient->request('get', $request_url);
// Check the response and handle the data accordingly.
if ($response->getStatusCode() == 200) {
// Request successful, handle the data in $response->data.
return [
"message" => "Get account data",
"accountData" => json_decode($response->getBody()->getContents(),
TRUE)['data'],
"message" => "WissKI Cloud account manager daemon is available.",
'success' => TRUE,
];
}
else {
// Request failed, handle the error.
return [
"message" => 'Request failed with code: ' . $response->getStatusCode(),
"accountData" => [
'accountWithUsername' => NULL,
'accountWithEmail' => NULL,
'accountWithSubdomain' => NULL,
],
"message" => 'WissKI Cloud account manager daemon is not available: ' . $response->getStatusCode(),
'success' => FALSE,
];
}
@ -243,90 +480,93 @@ class WisskiCloudAccountManagerDaemonApiActions {
// Request failed, handle the error.
$this->loggerFactory
->get('wisski_cloud_account_manager')
->error('Request failed with exception: ' . $e->getMessage());
->error('Something went wrong: ' . $e->getMessage());
$this->messenger
->addError($this->stringTranslation->translate('Can not communicate with the WissKI Cloud account manager daemon. Try again later or contact cloud@wiss-ki.eu.'));
return [
"message" => 'Request failed with exception: ' . $e->getMessage(),
"accountData" => [
'accountWithUsername' => NULL,
'accountWithEmail' => NULL,
'accountWithSubdomain' => NULL,
],
'success' => FALSE,
];
->addError($this->stringTranslation->translate('Can not communicate with the WissKI Cloud account manager daemon. Try again later or contact @adminMail.',
['@adminMail'
=> $this->ADMIN_EMAIL]));
}
}
/**
* Gets all accounts from the WissKI Cloud account manager daemon.
*
* Purges an account via the WissKI Cloud account manager daemon.
* Deletes the account from the accounts table and the Drupal user.
* Deletes the instance via the daemon from the WissKI Cloud.
* @param int $aid
* The account ID to purge.
* @return array
* The accounts response from the daemon.
* The response from the daemon.
*/
public function getAccounts(): array {
public function purgeAccount(int $aid) {
try {
// Combine the base URL and the query string.
$request_url = $this->DAEMON_URL . $this->ALL_ACCOUNTS;
// Send the GET request using the `drupal_http_request()` function.
$response = $this->httpClient->get($request_url);
return json_decode($response->getBody()->getContents(), TRUE);
// Get the account ID from the route.
// @todo Why is there a space in the account ID?
$aid = trim($aid);
// Delete the instance via the daemon from the WissKI Cloud.
$response = $this->crudInstance('delete', $aid);
if ($response['success']) {
// Delete the account and Drupal user.
$this->deleteAccount($aid);
$this->messenger
->addMessage($this->stringTranslation->translate('Account purged successfully.'));
return [
'data' => NULL,
'error' => NULL,
'message' => 'Account purged successfully.',
'success' => TRUE,
];
}
else {
if (!$response['error']) {
// No success and no error.
$this->messenger
->addMessage($this->stringTranslation->translate('Account not found or already purged.'));
return [
'data' => NULL,
'error' => NULL,
'message' => $response['message'],
'success' => FALSE,
];
}
else {
// No success and error.
$this->messenger
->addError($this->stringTranslation->translate('Something went wrong: ' . $response['message']));
$this->loggerFactory->get('wisski_cloud_account_manager')->error($response['error']);
return [
'data' => NULL,
'error' => $response['error'],
'message' => 'Something went wrong: ' . $response['message'],
'success' => FALSE,
];
}
}
}
catch (\Exception $e) {
// Request failed, handle the error.
$this->loggerFactory
->get('wisski_cloud_account_manager')
->error('Request failed with exception: ' . $e->getMessage());
$this->messenger
->addError($this->stringTranslation->translate('Can not communicate with the WissKI Cloud account manager daemon. Try again later or contact cloud@wiss-ki.eu.'));
return [
"message" => 'Request failed with exception: ' . $e->getMessage(),
"accounts" => [],
'success' => FALSE,
];
->addError($this->stringTranslation->translate('Something went wrong!' . $e->getMessage()));
}
}
/**
* Checks the validation status of the given validation code.
*
* @param string $validationCode
* The validation code to check.
*
* @return array
* The account data from the daemon.
*/
public function validateAccount(string $validationCode): array {
try {
$url = $this->DAEMON_URL . $this->ACCOUNT_VALIDATION_URL_PART . '/' . $validationCode;
$validationResponse = $this->httpClient->put($url);
return json_decode($validationResponse->getBody()
->getContents(), TRUE);
}
catch (\Exception $e) {
// Request failed, handle the error.
$this->loggerFactory
->get('wisski_cloud_account_manager')
->error('Request failed with exception: ' . $e->getMessage());
$this->messenger
->addError($this->stringTranslation->translate('Can not communicate with the WissKI Cloud account manager daemon. Try again later or contact cloud@wiss-ki.eu.'));
return [
"message" => 'Request failed with exception: ' . $e->getMessage(),
"accounts" => [],
'success' => FALSE,
];
}
}
/**
/**
* Sends a validation email to the given email address.
*
* @param string $email
* The email address to send the validation email to.
* @param string $personName
* The person name to be used in the validation email.
* @param string $validationCode
* The validation code to be used in the validation link.
*/
public function sendValidationEmail(string $email, string $validationCode): void {
public function sendValidationEmail(string $email, string $personName, string $validationCode): void {
try {
$module = 'wisski_cloud_account_manager';
$key = 'wisski_cloud_account_validation';
@ -336,17 +576,19 @@ class WisskiCloudAccountManagerDaemonApiActions {
$validationLink = $this->requestStack->getCurrentRequest()
->getSchemeAndHttpHost() . '/wisski-cloud-account-manager/validate/' . $validationCode;
$params['message'] = Markup::create($this->stringTranslation->translate('<p>Please validate your account by clicking on this <a href="@validationLink" target="_blank">link</a> or copy this to the address bar of your browser: <p>@validationLink</p>.</p>', ['@validationLink' => $validationLink]));
$params['subject'] = $this->stringTranslation->translate('WissKI Cloud account validation');
$result = $this->mailManager->mail($module, $key, $to, $langcode, $params, NULL, TRUE);
if ($result['result'] === TRUE) {
$this->messenger
->addMessage($this->stringTranslation->translate('Email send successfully.'));
}
else {
$this->messenger
->addMessage($this->stringTranslation->translate('There was an error sending the email.'), 'error');
$message = $this->twig->render('@wisski_cloud_account_manager/wisski-cloud-account-manager-validation-email.html.twig', [
'personName' => $personName,
'validationLink' => $validationLink,
]);
$params['subject'] = $this->stringTranslation->translate('WissKI Cloud account validation');
$params['message'] = Markup::create($message);
$result = $this->mailManager->mail($module, $key, $to, $langcode, $params, NULL, TRUE);
if ($result['result'] != TRUE) {
$this->loggerFactory
->get('wisski_cloud_account_manager')
->error('Email sending operation ended with error: ' . $result['message']);
}
}
catch (\Exception $e) {
@ -360,4 +602,58 @@ class WisskiCloudAccountManagerDaemonApiActions {
}
/**
* Validates the account.
*
* @param string $validationCode
* The validation code to check.
*
* @return array [uid, name]
*/
public function validateAccount(string $validationCode): array {
try {
$selectQuery = $this->database->select('wisski_cloud_account_manager_accounts', 'w')
->fields('w', ['aid', 'organisation', 'person_name', 'provisioned','subdomain', 'validation_code'])
->condition('w.validation_code', $validationCode, '=');
$selectQuery->join('users_field_data', 'u', 'w.uid = u.uid');
$selectQuery->fields('u', ['uid', 'name', 'mail', 'status']);
$account = $selectQuery->execute()->fetchAll(\PDO::FETCH_ASSOC);
if (isset($account[0]['status'])) {
if ($account[0]['status'] == 0) {
$updateQuery = $this->database->update('users_field_data')
->fields(['status' => 1])
->condition('uid', $account['0']['uid'], '=');
$updateQuery->execute();
$account = $selectQuery->execute()->fetchAll(\PDO::FETCH_ASSOC);
$this->messenger
->addMessage($this->stringTranslation->translate('Account validated successfully.'));
} else {
$this->messenger
->addMessage($this->stringTranslation->translate('Account already validated.'));
}
return [
'uid' => $account[0]['uid'],
'name' => $account[0]['name']];
}
else {
$this->messenger
->addError($this->stringTranslation->translate('Account validation failed. Please contact @adminEmail.',
['@adminEmail'
=> $this->ADMIN_EMAIL]));
return [];
}
}
catch (\Exception $e) {
// Request failed, handle the error.
$this->loggerFactory
->get('wisski_cloud_account_manager')
->error('Request failed with exception: ' . $e->getMessage());
$this->messenger
->addError($this->stringTranslation->translate('Can not communicate with the WissKI Cloud account manager daemon. Try again later or contact cloud@wiss-ki.eu.'));
return [];
}
}
}