diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..2a37794 --- /dev/null +++ b/css/style.css @@ -0,0 +1,43 @@ +/* Reset the table styles */ +table.wisski-cloud-account-manager-table { + border-collapse: collapse; + width: 100%; +} + +/* Style for table headers */ +table.wisski-cloud-account-manager-table th { + background-color: #f2f2f2; + padding: 8px; + text-align: center; +} + +/* Alternate row background color */ +table.wisski-cloud-account-manager-table tr:nth-child(even) { + background-color: #f2f2f2; +} + +/* Style for table cells */ +table.wisski-cloud-account-manager-table td { + padding: 8px; + border: 1px solid #dddddd; +} + +/* Center-align certain cells */ +table.wisski-cloud-account-manager-table td.valid, +table.wisski-cloud-account-manager-table td.provisioned { + text-align: center; +} + +.wisski-cloud-account-manager-success { + background-color: green; +} +.wisski-cloud-account-manager-warning { + background-color: orange; +} +.wisski-cloud-account-manager-error { + background-color: red; +} + +.wisski-cloud-account-manager-center { + text-align: center; +} diff --git a/src/Controller/WisskiCloudAccountManagerController.php b/src/Controller/WisskiCloudAccountManagerController.php index efdd4fc..da9aaed 100644 --- a/src/Controller/WisskiCloudAccountManagerController.php +++ b/src/Controller/WisskiCloudAccountManagerController.php @@ -3,23 +3,79 @@ namespace Drupal\wisski_cloud_account_manager\Controller; use Drupal\Core\Controller\ControllerBase; +use Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * The Wisski Cloud account manager info controller. */ class WisskiCloudAccountManagerController extends ControllerBase { + /** + * @var \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions + * The WissKi Cloud account manager daemon API actions service. + */ + protected WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions; + + /** + * 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'), + ); + } + /** * Info page for terms and conditions. * * @return array * The page build array. */ - public function termsAndConditions(): array { + public function termsAndConditionsPage(): array { $build = [ '#markup' => $this->t('Hello World!'), ]; return $build; } + /** + * Page to check the validation and provision status. + * + * @param string $validationCode + * The token to check the status for. + * + * @return array + * The page build array. + */ + public function validationPage(string $validationCode): array { + $validationResponse = $this->wisskiCloudAccountManagerDaemonApiActions->validateAccount($validationCode); + + $responseContents = json_decode($validationResponse->getBody() + ->getContents(), TRUE); + + return [ + '#theme' => 'wisski_cloud_account_manager_validation_page', + '#responseContents' => $responseContents, + '#attached' => [ + 'library' => [ + 'wisski_cloud_account_manager/wisski_cloud_account_manager', + ], + ], + ]; + } + } diff --git a/src/Form/WisskiCloudAccountManagerCreateForm.php b/src/Form/WisskiCloudAccountManagerCreateForm.php index 447220c..9ef2c95 100644 --- a/src/Form/WisskiCloudAccountManagerCreateForm.php +++ b/src/Form/WisskiCloudAccountManagerCreateForm.php @@ -2,6 +2,7 @@ namespace Drupal\wisski_cloud_account_manager\Form; +use Drupal\Component\Utility\EmailValidatorInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions; @@ -18,10 +19,16 @@ class WisskiCloudAccountManagerCreateForm extends FormBase { */ protected WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions; + /** + * @var \Drupal\Component\Utility\EmailValidatorInterface + * The email validator service. + */ + private EmailValidatorInterface $emailValidator; + /** * {@inheritdoc} */ - public function getFormId() { + public function getFormId(): string { return 'wisski_cloud_account_manager_create'; } @@ -30,9 +37,12 @@ class WisskiCloudAccountManagerCreateForm extends FormBase { * * @param \Drupal\wisski_cloud_account_manager\WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions * The WissKi Cloud account manager daemon API actions service. + * @param \Drupal\Component\Utility\EmailValidatorInterface $emailValidator + * The email validator service. */ - public function __construct(WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions) { + public function __construct(WisskiCloudAccountManagerDaemonApiActions $wisskiCloudAccountManagerDaemonApiActions, EmailValidatorInterface $emailValidator) { $this->wisskiCloudAccountManagerDaemonApiActions = $wisskiCloudAccountManagerDaemonApiActions; + $this->emailValidator = $emailValidator; } /** @@ -44,6 +54,7 @@ class WisskiCloudAccountManagerCreateForm extends FormBase { public static function create(ContainerInterface $container) { return new static( $container->get('wisski_cloud_account_manager.daemon_api.actions'), + $container->get('email.validator'), ); } @@ -126,20 +137,20 @@ class WisskiCloudAccountManagerCreateForm extends FormBase { $response = $this->wisskiCloudAccountManagerDaemonApiActions->checkAccountData($dataToCheck); - if ($response['accountData']['userWithUsername']) { + if ($response['accountData']['accountWithUsername']) { $form_state->setErrorByName('username', $this->t('The username "@username" is already in use.', ['@username' => $dataToCheck['username']])); } - if ($response['accountData']['userWithEmail']) { + if ($response['accountData']['accountWithEmail']) { $form_state->setErrorByName('email', $this->t('The email "@email" is already in use.', ['@email' => $dataToCheck['email']])); } - if ($response['accountData']['userWithSubdomain']) { + if ($response['accountData']['accountWithSubdomain']) { $form_state->setErrorByName('subdomain', $this->t('The subdomain "@subdomain" is already in use.', ['@subdomain' => $dataToCheck['subdomain']])); } // Check if email is in valid form. - if (!\Drupal::service('email.validator')->isValid($dataToCheck['email'])) { + if (!$this->emailValidator->isValid($dataToCheck['email'])) { $form_state->setErrorByName('email', $this->t('Email not in valid form, i.e. "name@example.com".')); } } @@ -160,13 +171,13 @@ class WisskiCloudAccountManagerCreateForm extends FormBase { $accountResponse = $this->wisskiCloudAccountManagerDaemonApiActions->addAccount($account); dpm($accountResponse, 'accountResponse'); - $this->wisskiCloudAccountManagerDaemonApiActions->sendValidationEmail($accountResponse['user']['email'], $accountResponse['user']['validationCode']); + $this->wisskiCloudAccountManagerDaemonApiActions->sendValidationEmail($accountResponse['account']['email'], $accountResponse['account']['validationCode']); - \Drupal::messenger() + $this->messenger() ->addMessage($this->t('The account data has been successfully saved, please check your email for validation!')); } catch (\Exception $ex) { - \Drupal::logger('wisski_cloud_account_manager')->error($ex->getMessage()); + $this->logger('wisski_cloud_account_manager')->error($ex->getMessage()); } } diff --git a/src/Form/WisskiCloudAccountManagerSettingsForm.php b/src/Form/WisskiCloudAccountManagerSettingsForm.php index c32cf81..6ece673 100644 --- a/src/Form/WisskiCloudAccountManagerSettingsForm.php +++ b/src/Form/WisskiCloudAccountManagerSettingsForm.php @@ -42,18 +42,25 @@ class WisskiCloudAccountManagerSettingsForm extends ConfigFormBase { '#default_value' => $config->get('daemonUrl'), ]; - $form['userPostUrlPath'] = [ + $form['accountPostUrlPath'] = [ '#type' => 'url', '#title' => $this->t('POST URL path'), - '#description' => $this->t('Provide the path to the POST endpoint, i. e. "/user"'), - '#default_value' => $config->get('userPostUrlPath'), + '#description' => $this->t('Provide the path to the POST endpoint, i. e. "/account"'), + '#default_value' => $config->get('accountPostUrlPath'), ]; - $form['userFilterByData'] = [ + $form['accountFilterByData'] = [ '#type' => 'url', '#title' => $this->t('Filter by Data URL path'), - '#description' => $this->t('Provide the path to the Get user by data endpoint, i. e. "/user/by_data"'), - '#default_value' => $config->get('userFilterByData'), + '#description' => $this->t('Provide the path to the Get account by data endpoint, i. e. "/account/by_data"'), + '#default_value' => $config->get('accountFilterByData'), + ]; + + $form['accountValidation'] = [ + '#type' => 'url', + '#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'), ]; return $form; @@ -66,8 +73,10 @@ class WisskiCloudAccountManagerSettingsForm extends ConfigFormBase { $config = $this->config('wisski_cloud_account_manager.settings'); $config->set('daemonURL', $form_state->getValue('daemonURL')) - ->set('userPostUrlPath', $form_state->getValue('userPostUrlPath')) - ->set('userFilterByData', $form_state->getValue('userFilterByData')) + ->set('accountPostUrlPath', $form_state->getValue('accountPostUrlPath')) + ->set('accountFilterByData', $form_state->getValue('accountFilterByData')) + ->set('accountProvisionAndValidationCheck', $form_state->getValue('accountProvisionAndValidationCheck')) + ->set('accountValidation', $form_state->getValue('accountValidation')) ->save(); parent::submitForm($form, $form_state); diff --git a/src/WisskiCloudAccountManagerDaemonApiActions.php b/src/WisskiCloudAccountManagerDaemonApiActions.php index 8bc0b70..1ac70cd 100644 --- a/src/WisskiCloudAccountManagerDaemonApiActions.php +++ b/src/WisskiCloudAccountManagerDaemonApiActions.php @@ -11,6 +11,7 @@ use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Render\Markup; use Drupal\Core\StringTranslation\TranslationInterface; use GuzzleHttp\ClientInterface; +use Psr\Http\Message\ResponseInterface; /** * Handles the communication with the WissKI Cloud account manager daemon. @@ -31,14 +32,21 @@ class WisskiCloudAccountManagerDaemonApiActions { * * @var string */ - private string $USER_POST_URL_PART = '/user'; + private string $ACCOUNT_POST_URL_PART = '/account'; /** * The URL path to the GET endpoint. * * @var string */ - private string $FILTER_BY_DATA_URL_PART = '/user/by_data'; + private string $FILTER_BY_DATA_URL_PART = '/account/by_data'; + + /** + * The URL path to provision and validation GET endpoint. + * + * @var string + */ + private string $ACCOUNT_VALIDATION_URL_PART = '/account/validation'; /** * The string translation service. @@ -68,8 +76,6 @@ class WisskiCloudAccountManagerDaemonApiActions { */ protected Config $settings; - - /** * The mail manager. * @@ -93,7 +99,8 @@ class WisskiCloudAccountManagerDaemonApiActions { ClientInterface $httpClient, ConfigFactoryInterface $configFactory, MailManagerInterface $mailManager, - LanguageManagerInterface $languageManager) { + LanguageManagerInterface $languageManager + ) { // Services from container. $this->stringTranslation = $stringTranslation; $this->messenger = $messenger; @@ -108,9 +115,10 @@ class WisskiCloudAccountManagerDaemonApiActions { // 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->USER_POST_URL_PART = $settings->get('userPostUrlPath') ?: '/user'; - $this->FILTER_BY_DATA_URL_PART = $settings->get('userFilterByData') ?: '/user/by_data'; - + $this->USER_POST_URL_PART = $settings->get('accountPostUrlPath') ?: '/account'; + $this->FILTER_BY_DATA_URL_PART = $settings->get('accountFilterByData') ?: '/account/by_data'; + $this->USER_PROVISION_AND_VALIDATION_URL_PART = $settings->get('accountProvisionAndValidationUrlPart') ?: '/account/provision_and_validation'; + $this->ACCOUNT_VALIDATION_URL_PART = $settings->get('accountValidationUrlPart') ?: '/account/validation'; } /** @@ -120,7 +128,7 @@ class WisskiCloudAccountManagerDaemonApiActions { * The account to add. * * @return array - * The response from the daemon (user id with validation code). + * The response from the daemon (account id with validation code). */ public function addAccount(array $account): array { $request = [ @@ -129,21 +137,25 @@ class WisskiCloudAccountManagerDaemonApiActions { ], 'body' => json_encode($account), ]; - $userPostUrl = $this->DAEMON_URL . $this->USER_POST_URL_PART; - $response = $this->httpClient->post($userPostUrl, $request); - return array_merge(json_decode($response->getBody()->getContents(), TRUE), ['statusCode' => $response->getStatusCode()]); + $accountPostUrl = $this->DAEMON_URL . $this->ACCOUNT_POST_URL_PART; + $response = $this->httpClient->post($accountPostUrl, $request); + return array_merge(json_decode($response->getBody() + ->getContents(), TRUE), ['statusCode' => $response->getStatusCode()]); } /** * Check if an account with the given data already exists. * * @param array $dataToCheck - * The data to check. + * The data to check. Possible keys are: + * - email + * - subdomain + * - username. * * @return array * The response from the daemon. */ - public function checkAccountData($dataToCheck): array { + public function checkAccountData(array $dataToCheck): array { // Build the query string from the parameters. $query_string = http_build_query($dataToCheck); @@ -170,6 +182,22 @@ class WisskiCloudAccountManagerDaemonApiActions { } } + /** + * Checks the validation status of the given validation code. + * + * @param string $validationCode + * The validation code to check. + * + * @return \Psr\Http\Message\ResponseInterface + * The response from the daemon. + */ + public function validateAccount(string $validationCode): ResponseInterface { + $url = $this->DAEMON_URL . $this->ACCOUNT_VALIDATION_URL_PART . '/' . $validationCode; + return $this->httpClient->put($url); + + } + + /** * Sends a validation email to the given email address. * @@ -184,7 +212,8 @@ class WisskiCloudAccountManagerDaemonApiActions { $langcode = $this->languageManager->getDefaultLanguage()->getId(); $to = $email; - $validationLink = \Drupal::request()->getSchemeAndHttpHost() . '/wisski-cloud-account-manager/validate/' . $validationCode; + $validationLink = \Drupal::request() + ->getSchemeAndHttpHost() . '/wisski-cloud-account-manager/validate/' . $validationCode; $params['message'] = Markup::create($this->stringTranslation->translate('

Please validate your account by clicking on this link or copy this to the address bar of your browser:

@validationLink

.

', ['@validationLink' => $validationLink])); $params['subject'] = $this->stringTranslation->translate('WissKI Cloud account validation'); diff --git a/templates/wisski-cloud-account-manager-validation-page.html.twig b/templates/wisski-cloud-account-manager-validation-page.html.twig new file mode 100644 index 0000000..cab9176 --- /dev/null +++ b/templates/wisski-cloud-account-manager-validation-page.html.twig @@ -0,0 +1,52 @@ +{# wisski_cloud_account_manager/templates/wisski_cloud_account_manager_validation_page.html.twig #} +
+ {% if responseContents is not empty %} + + + + + + + + + + + + + + + + + +
Person nameEmailUsernameSubdomainValidProvisioned
{{ responseContents.data.personName }}{{ responseContents.data.email }}{{ responseContents.data.username }}{{ responseContents.data.subdomain }} + {% if responseContents.data.valid == 1 %} + yes + {% elseif responseContents.data.valid == 0 %} + no + {% else %} + unknown + {% endif %} + {% if responseContents.data.provisioned == 1 %} + yes + {% elseif responseContents.data.provisioned == 0 %} + no + {% elseif responseContents.data.provisioned == 2 %} + ongoing + {% else %} + unknown + {% endif %}
+
+
+ {% if responseContents.data.valid == 1 and responseContents.data.provisioned == 1 %} + + {% elseif responseContents.data.valid == 1 and responseContents.data.provisioned == 0 %} + + {% elseif responseContents.data.valid == 0 %} + + {% else %} + + {% endif %} +
+ + {% endif %} +
diff --git a/wisski_cloud_account_manager.libraries.yml b/wisski_cloud_account_manager.libraries.yml new file mode 100644 index 0000000..8fb6984 --- /dev/null +++ b/wisski_cloud_account_manager.libraries.yml @@ -0,0 +1,5 @@ +wisski_cloud_account_manager: + version: 1.x + css: + theme: + css/style.css: {} diff --git a/wisski_cloud_account_manager.module b/wisski_cloud_account_manager.module index 6d1d99b..4ad28ea 100644 --- a/wisski_cloud_account_manager.module +++ b/wisski_cloud_account_manager.module @@ -42,3 +42,15 @@ function wisski_cloud_account_manager_mail($key, &$message, $params) { break; } } + +/** + * Implements hook_theme(). + */ +function wisski_cloud_account_manager_theme($existing, $type, $theme, $path) { + return [ + 'wisski_cloud_account_manager_validation_page' => [ + 'variables' => ['responseContents' => NULL], + ], + ]; +} + diff --git a/wisski_cloud_account_manager.routing.yml b/wisski_cloud_account_manager.routing.yml index 1643fb1..23414a8 100644 --- a/wisski_cloud_account_manager.routing.yml +++ b/wisski_cloud_account_manager.routing.yml @@ -23,10 +23,22 @@ wisski_cloud_account.create: requirements: _access: 'TRUE' +wisski_cloud_account.validate: + path: '/wisski-cloud-account-manager/validate/{validationCode}' + defaults: + _controller: '\Drupal\wisski_cloud_account_manager\Controller\WisskiCloudAccountManagerController::validationPage' + _title: 'Check validation and provision of your WissKI Cloud account' + requirements: + _access: 'TRUE' + token: '[a-zA-Z0-9]+' + wisski_cloud_account.terms_and_conditions: path: '/wisski-cloud-account-manager/terms-and-conditions' defaults: - _controller: '\Drupal\wisski_cloud_account_manager\Controller\WisskiCloudAccountManagerController::termsAndConditions' + _controller: '\Drupal\wisski_cloud_account_manager\Controller\WisskiCloudAccountManagerController::termsAndConditionsPage' _title: 'Terms and conditions' requirements: _access: 'TRUE' + + +