Verified Commit 9432bd62 authored by Dave Long's avatar Dave Long
Browse files

feat: #3481627 Update user creation form to hide password and status fields when user is notified

By: pameeela
By: xjm
By: lauriii
By: poker10
By: catch
By: longwave
By: dpi
By: alexanderpas
By: neomenlo
By: clemens.tolboom
By: sergiur
By: lostcarpark
By: phenaproxima
By: acbramley
By: quietone
By: danielveza
By: nod_
By: larowlan
parent d07f6af6
Loading
Loading
Loading
Loading
+17 −7
Changes for core/modules/user/src/AccountForm.php: 17 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -123,6 +123,13 @@ public function form(array $form, FormStateInterface $form_state) {
      '#access' => $account->name->access('edit'),
    ];

    $form['account']['notify'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Email user with password setup instructions'),
      '#access' => $admin_create,
      '#default_value' => $admin_create,
    ];

    // Display password field only for existing users or when user is allowed to
    // assign a password during registration.
    if (!$register) {
@@ -175,7 +182,11 @@ public function form(array $form, FormStateInterface $form_state) {
        '#type' => 'password_confirm',
        '#size' => 25,
        '#description' => $this->t('Provide a password for the new account in both fields.'),
        '#required' => TRUE,
        '#states' => [
          'invisible' => [
            ':input[name="notify"]' => ['checked' => TRUE],
          ],
        ],
      ];
    }

@@ -202,6 +213,11 @@ public function form(array $form, FormStateInterface $form_state) {
      '#default_value' => $status,
      '#options' => [$this->t('Blocked'), $this->t('Active')],
      '#access' => $account->status->access('edit') && $user->id() !== $account->id(),
      '#states' => [
        'invisible' => [
          ':input[name="notify"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $roles = Role::loadMultiple();
@@ -222,12 +238,6 @@ public function form(array $form, FormStateInterface $form_state) {
      '#disabled' => TRUE,
    ];

    $form['account']['notify'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Notify user of new account'),
      '#access' => $admin_create,
    ];

    $user_preferred_langcode = $register ? $language_interface->getId() : $account->getPreferredLangcode();

    $user_preferred_admin_langcode = $register ? $language_interface->getId() : $account->getPreferredAdminLangcode(FALSE);
+6 −1
Changes for core/modules/user/src/RegisterForm.php: 6 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -112,8 +112,13 @@ protected function actions(array $form, FormStateInterface $form_state) {
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $admin = $form_state->getValue('administer_users');
    $notify = !$form_state->isValueEmpty('notify');

    if (!\Drupal::config('user.settings')->get('verify_mail') || $admin) {
    // Use the submitted password only when the password field is accessible:
    // either self-registration with email verification disabled, or admin
    // creation without the notification checkbox. In all other cases, generate
    // a random password so the user must set their own via email.
    if (($admin && !$notify) || !\Drupal::config('user.settings')->get('verify_mail')) {
      $pass = $form_state->getValue('pass');
    }
    else {
+57 −0
Changes for core/modules/user/tests/src/Functional/UserCreateTest.php: 57 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -143,4 +143,61 @@ public function testUserAdd(): void {
    $this->assertSession()->pageTextNotContains('Password field is required');
  }

  /**
   * Tests that the password is discarded when notify is enabled.
   */
  public function testUserAddPasswordWithNotify(): void {
    $admin = $this->drupalCreateUser(['administer users']);
    $this->drupalLogin($admin);

    $password_checker = \Drupal::service('password');
    $typed_pass = 'known_password_for_testing';

    // Create a user with notify enabled and a password filled in.
    // The typed password should be discarded.
    $name_notify = $this->randomMachineName();
    $edit = [
      'name' => $name_notify,
      'mail' => $this->randomMachineName() . '@example.com',
      'pass[pass1]' => $typed_pass,
      'pass[pass2]' => $typed_pass,
      'notify' => TRUE,
    ];
    $this->drupalGet('admin/people/create');
    $this->submitForm($edit, 'Create new account');
    $this->assertSession()->pageTextContains('A welcome message with further instructions has been emailed to the new user ' . $name_notify . '.');

    $users = \Drupal::entityTypeManager()
      ->getStorage('user')
      ->loadByProperties(['name' => $name_notify]);
    $user_notify = reset($users);

    // The stored password should not match the typed password.
    $this->assertFalse($password_checker->check($typed_pass, $user_notify->getPassword()), 'Typed password is not used when notify is enabled.');
    // The stored password should not be a hash of an empty string.
    $this->assertFalse($password_checker->check('', $user_notify->getPassword()), 'Password is not a hash of an empty string when notify is enabled.');

    // Create a user with notify disabled and a password filled in.
    // The typed password should be used.
    $name_no_notify = $this->randomMachineName();
    $edit = [
      'name' => $name_no_notify,
      'mail' => $this->randomMachineName() . '@example.com',
      'pass[pass1]' => $typed_pass,
      'pass[pass2]' => $typed_pass,
      'notify' => FALSE,
    ];
    $this->drupalGet('admin/people/create');
    $this->submitForm($edit, 'Create new account');
    $this->assertSession()->pageTextContains('Created a new user account for ' . $name_no_notify . '. No email has been sent.');

    $users = \Drupal::entityTypeManager()
      ->getStorage('user')
      ->loadByProperties(['name' => $name_no_notify]);
    $user_no_notify = reset($users);

    // The stored password should match the typed password.
    $this->assertTrue($password_checker->check($typed_pass, $user_no_notify->getPassword()), 'Typed password is used when notify is disabled.');
  }

}
+1 −0
Changes for core/modules/user/tests/src/Functional/UserRolesAssignmentTest.php: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ public function testCreateUserWithRole(): void {
      'pass[pass1]' => $pass = $this->randomString(),
      'pass[pass2]' => $pass,
      "roles[$rid]" => $rid,
      'notify' => FALSE,
    ];
    $this->drupalGet('admin/people/create');
    $this->submitForm($edit, 'Create new account');
+0 −7
Changes for core/modules/user/tests/src/Kernel/UserAccountFormFieldsTest.php: 0 added lines, 7 removed lines.
Original line number Diff line number Diff line
@@ -105,25 +105,18 @@ public function testUserEditForm(): void {
   * @internal
   */
  protected function assertFieldOrder(array $elements): void {
    $name_index = 0;
    $name_weight = 0;
    $pass_index = 0;
    $pass_weight = 0;
    $index = 0;
    foreach ($elements as $key => $element) {
      if ($key === 'name') {
        $name_index = $index;
        $name_weight = $element['#weight'];
        $this->assertTrue($element['#sorted'], "'name' field is #sorted.");
      }
      elseif ($key === 'pass') {
        $pass_index = $index;
        $pass_weight = $element['#weight'];
        $this->assertTrue($element['#sorted'], "'pass' field is #sorted.");
      }
      $index++;
    }
    $this->assertEquals($pass_index - 1, $name_index, "'name' field ({$name_index}) appears before 'pass' field ({$pass_index}).");
    $this->assertLessThan($pass_weight, $name_weight, "'name' field weight ($name_weight) should be smaller than 'pass' field weight ($pass_weight).");
  }

Loading