diff --git a/config/install/user_registrationpassword.mail.yml b/config/install/user_registrationpassword.mail.yml index 00ea1db..f60f750 100644 --- a/config/install/user_registrationpassword.mail.yml +++ b/config/install/user_registrationpassword.mail.yml @@ -1,4 +1,7 @@ register_confirmation_with_pass: body: "[user:display-name],\r\n\r\nThank you for registering at [site:name]. You may now log in and verify your account by clicking this link or copying and pasting it to your browser:\r\n\r\n[user:registrationpassword-url]\r\n\r\nThis link can only be used once. You will be able to log in at [site:login-url] in the future using:\r\n\r\nusername: [user:name]\r\npassword: your password\r\n\r\n-- [site:name] team" subject: 'Account details for [user:display-name] at [site:name]' +register_confirmation_admin_created: + body: "[user:display-name],\n\nA site administrator at [site:name] has created an account for you. You may now log in by clicking this link or copying and pasting it into your browser:\n\n[user:registrationpassword-url]\n\nBy visiting the site your account will be activated and you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: your password\n\n-- [site:name] team" + subject: 'An administrator created an account for you at [site:name]' langcode: en diff --git a/config/install/user_registrationpassword.settings.yml b/config/install/user_registrationpassword.settings.yml index 7214fd8..2733767 100644 --- a/config/install/user_registrationpassword.settings.yml +++ b/config/install/user_registrationpassword.settings.yml @@ -3,4 +3,5 @@ registration_ftll_expire: false registration_ftll_timeout: 86400 notify: register_confirmation_with_pass: true + register_confirmation_admin_created: true registration_redirect: '' diff --git a/config/schema/user_registrationpassword.schema.yml b/config/schema/user_registrationpassword.schema.yml index b0411b9..72281e6 100644 --- a/config/schema/user_registrationpassword.schema.yml +++ b/config/schema/user_registrationpassword.schema.yml @@ -20,6 +20,9 @@ user_registrationpassword.settings: register_confirmation_with_pass: type: boolean label: 'User registration email with password set' + register_confirmation_admin_created: + type: boolean + label: 'User registration email by admin with confirmation' registration_redirect: type: path label: 'Redirect path on registration' @@ -31,6 +34,9 @@ user_registrationpassword.mail: register_confirmation_with_pass: type: mail label: 'User registration email with password set' + register_confirmation_admin_created: + type: mail + label: 'User registration email by admin with confirmation' user_registrationpassword.mail_original: type: config_object diff --git a/tests/src/Kernel/UserRegistrationPasswordMailNotifyTest.php b/tests/src/Kernel/UserRegistrationPasswordMailNotifyTest.php index 4c2939a..aefde08 100644 --- a/tests/src/Kernel/UserRegistrationPasswordMailNotifyTest.php +++ b/tests/src/Kernel/UserRegistrationPasswordMailNotifyTest.php @@ -32,6 +32,7 @@ class UserRegistrationPasswordMailNotifyTest extends EntityKernelTestBase { public static function userRegistrationMailsProvider(): array { return [ ['register_confirmation_with_pass', ['register_confirmation_with_pass']], + ['register_confirmation_admin_created', ['register_confirmation_admin_created']], ]; } diff --git a/user_registrationpassword.module b/user_registrationpassword.module index af83384..6df8e42 100644 --- a/user_registrationpassword.module +++ b/user_registrationpassword.module @@ -95,7 +95,7 @@ function user_registrationpassword_form_user_admin_settings_alter(&$form, FormSt // Render email template settings. $form['email_user_registrationpassword'] = [ '#type' => 'details', - '#title' => t('Welcome (no approval required, password is set)'), + '#title' => t('Welcome (confirmation)'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#description' => t('Edit the welcome email messages sent to new members upon registering, when no administrator approval is required and password has already been set.') . ' ' . $email_token_help, @@ -113,6 +113,28 @@ function user_registrationpassword_form_user_admin_settings_alter(&$form, FormSt '#default_value' => $mail_config->get('register_confirmation_with_pass.body'), '#rows' => 15, ]; + + // Admin create user without confirmation (user enabled). + $form['email_user_registrationpassword_admin'] = [ + '#type' => 'details', + '#title' => t('Welcome (confirmation) (created by administrator)'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#description' => t('Edit the welcome email messages sent to new members upon registering, when no administrator approval is required and password has already been set.') . ' ' . $email_token_help, + '#group' => 'email', + ]; + $form['email_user_registrationpassword_admin']['user_registrationpassword_register_confirmation_admin_created_subject'] = [ + '#type' => 'textfield', + '#title' => t('Subject'), + '#default_value' => $mail_config->get('register_confirmation_admin_created.subject'), + '#maxlength' => 180, + ]; + $form['email_user_registrationpassword_admin']['user_registrationpassword_register_confirmation_admin_created_body'] = [ + '#type' => 'textarea', + '#title' => t('Body'), + '#default_value' => $mail_config->get('register_confirmation_admin_created.body'), + '#rows' => 15, + ]; // Reorder the form items back to their original order. $form['anonymous_settings']['#weight'] = -2; @@ -217,6 +239,10 @@ function user_registrationpassword_admin_settings_submit(&$form, FormStateInterf $mail_config ->set('register_confirmation_with_pass.subject', $form_state->getValue('user_registrationpassword_register_confirmation_with_pass_subject')) ->set('register_confirmation_with_pass.body', $form_state->getValue('user_registrationpassword_register_confirmation_with_pass_body')); + + $mail_config + ->set('register_confirmation_admin_created.subject', $form_state->getValue('user_registrationpassword_register_confirmation_admin_created_subject')) + ->set('register_confirmation_admin_created.body', $form_state->getValue('user_registrationpassword_register_confirmation_admin_created_body')); // Save or revert expiration limits variables. $config @@ -257,6 +283,9 @@ function user_registrationpassword_module_implements_alter(&$implementations, $h function user_registrationpassword_form_user_register_form_alter(&$form, FormStateInterface $form_state, $form_id) { /** @var \Drupal\user\UserInterface $account */ $account = $form_state->getFormObject()->getEntity(); + // Do not use the core access check result that's stored in the form. + $admin = $account->access('create'); + // Load configs. $user_config = \Drupal::config('user.settings'); $config = \Drupal::configFactory()->get('user_registrationpassword.settings'); @@ -275,28 +304,68 @@ function user_registrationpassword_form_user_register_form_alter(&$form, FormSta $form['actions']['submit']['#submit'][] = 'user_registrationpassword_form_user_register_set_password'; } - // Prevent this from being run if approval with password on registration - // form is set and the user is an anonymous user registering to the site. - // When admin users create a user, this does not need to be executed. - // And when this also does not need to be executed 'user_register' is not set - // as 'Visitors can create accounts and no administrator approval is - // required.' User registers, receives user_registrationpass email, would - // not make sense. Cause that will unblock the user Without - // the admin 'approving'. + // If this is a new user and the module is set up to function correctly. if ($user_config->get('register') == UserInterface::REGISTER_VISITORS && $config->get('registration') == UserRegistrationPassword::VERIFICATION_PASS && $account->isNew()) { - // Set the user account to blocked. - $form['account']['status']['#default_value'] = 0; + + // Add the 'administer_users' element from core user if it does not exist. + if (!isset($form['administer_users'])) { + // Pass access information to the submit handler. Running an access check + // inside the submit function interferes with form processing and breaks + // hook_form_alter(). + $form['administer_users'] = [ + '#type' => 'value', + '#value' => $admin, + ]; + } + + if ($admin) { + // Drop access to the core notify widget. + $form['account']['notify']['#access'] = FALSE; + // Add our status comment. + $form['account']['status']['#description'] = t('When Status is set to Blocked and Notify the user is checked a confirmation email is sent to the user to confirm and enable their account.'); + // This replaces the notify widget, so we can block anything core sends. + $form['account']['notifyregister'] = [ + '#type' => 'checkbox', + '#title' => t('Notify user of new account'), + '#access' => $admin, + ]; + // Register our validation handler. + $form['#validate'][] = 'user_registrationpassword_form_user_register_validate'; + } + else { + // Set the user account to blocked. + $form['account']['status']['#default_value'] = 0; + } + // Suppress any notification. $form['account']['notify']['#default_value'] = 0; - // Register our validate and submit handlers. + // Register our submit handler. $form['actions']['submit']['#submit'][] = 'user_registrationpassword_form_user_register_submit'; } } /** - * Implements submission handler for the user registration form. + * Implements validation handler for the user registration form. + * + * @see user_registrationpassword_form_user_register_form_alter() + */ +function user_registrationpassword_form_user_register_validate(&$form, FormStateInterface $form_state) { + $admin = $form_state->getValue('administer_users'); + $status = $form_state->getValue('status'); + $notifyregister = !$form_state->isValueEmpty('notifyregister'); + /** @var \Drupal\user\UserInterface $account */ + $account = $form_state->getFormObject()->getEntity(); + // If an admin creates an account - and it's set to enabled - and the admin + // checks the notifyregister checkbox we need to re-enable core notify. + if ($admin && $notifyregister && $status) { + $form_state->setValue('notify', TRUE); + } +} + +/** + * Implements submit handler for the user registration form. * * @see user_register_form() * @see user_registrationpassword_form_user_register_form_alter() @@ -317,28 +386,63 @@ function user_registrationpassword_form_user_register_set_password(&$form, FormS * @see user_registrationpassword_form_user_register_form_alter() */ function user_registrationpassword_form_user_register_submit(&$form, FormStateInterface $form_state) { + $user_config = \Drupal::config('user.settings'); + $config = \Drupal::configFactory()->get('user_registrationpassword.settings'); + $admin = $form_state->getValue('administer_users'); + + /** @var \Drupal\user\UserInterface $account */ + $account = $form_state->getFormObject()->getEntity(); + + // Test if this is run by an admin. + $admin_create = $account->access('create'); + + $notify = !$form_state->isValueEmpty('notify'); + + if ($admin_create && $notify) { + // No need to do anything when core notify is set while admin creates. + // Notify: true is set by the validation handler when an admin creates an + // account in state: enabled. + return; + } + + $params['account'] = $account; + // Define the message we need to remove. - // Yes, this throws a code style error, but this is in core. - // See user.module, that string contains a
. - $message = t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.
In the meantime, a welcome message with further instructions has been sent to your email address.'); - - // Unset all messages that contain the $message. - $messenger = \Drupal::messenger(); - // Cannot delete a single message, getting all and re-setting but the - // one from the core user register form. - foreach ($messenger->deleteByType(MessengerInterface::TYPE_STATUS) as $statusmessage) { - if (!((string) $message == (string) $statusmessage)) { - $messenger->addStatus($statusmessage); + if (!$admin_create) { + $message = t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.
In the meantime, a welcome message with further instructions has been sent to your email address.'); + } + elseif ($admin_create) { + $notifyregister = !$form_state->isValueEmpty('notifyregister'); + // If notifyregister is checked and the account is disabled. + if ($notifyregister && !$account->isActive()) { + $message = t('Created a new user account for %name. No email has been sent.', [':url' => $account->toUrl()->toString(), '%name' => $account->getAccountName()]); } } + + if (isset($message)) { + // Unset all messages that contain the $message. + $messenger = \Drupal::messenger(); + // Cannot delete a single message, getting all and re-setting but the + // one from the core user register form. + foreach ($messenger->deleteByType(MessengerInterface::TYPE_STATUS) as $statusmessage) { + if (!((string) $message == (string) $statusmessage)) { + $messenger->addStatus($statusmessage); + } + } + } // Notify the user. - /** @var \Drupal\user\UserInterface $account */ - $account = $form_state->getFormObject()->getEntity(); - // Send the confirmation email. - _user_registrationpassword_mail_notify('register_confirmation_with_pass', $account); - // Set success message and redirect to the front page. - \Drupal::messenger()->addMessage(t('A welcome message with further instructions has been sent to your email address.')); + if ($admin_create) { + if ($notifyregister && !$account->isActive()) { + _user_registrationpassword_mail_notify('register_confirmation_admin_created', $account); + \Drupal::service('messenger')->addStatus(t('A welcome message with further instructions has been emailed to the new user %name.', [':url' => $account->toUrl()->toString(), '%name' => $account->getAccountName()])); + } + } + else { + // Send the confirmation mail to the user. + _user_registrationpassword_mail_notify('register_confirmation_with_pass', $account); + \Drupal::service('messenger')->addMessage(t('A welcome message with further instructions has been sent to your email address.')); + } } /** @@ -567,7 +671,7 @@ function _user_registrationpassword_user_pass_submit(&$form, FormStateInterface } } else { - // If we found no errors execute core submission handler. + // If we found no errors execute core submit handler. // Obviously cache is disabled on this pages, so this should work. if (empty($_SESSION['messages']['error'])) { $core_submit = new UserPasswordForm(\Drupal::entityTypeManager()->getStorage('user'), \Drupal::languageManager(), \Drupal::configFactory(), \Drupal::flood(), \Drupal::typedDataManager(), \Drupal::service('email.validator'));