783 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			783 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
/**
 | 
						|
 * @file
 | 
						|
 */
 | 
						|
 | 
						|
use Drupal\Component\Utility\Crypt;
 | 
						|
use Drupal\Component\Utility\Unicode;
 | 
						|
use Drupal\Core\Access\AccessibleInterface;
 | 
						|
use Drupal\Core\Batch\BatchBuilder;
 | 
						|
use Drupal\Core\Form\FormStateInterface;
 | 
						|
use Drupal\Core\Render\Element;
 | 
						|
use Drupal\Core\Session\AccountInterface;
 | 
						|
use Drupal\Core\Session\AnonymousUserSession;
 | 
						|
use Drupal\Core\Site\Settings;
 | 
						|
use Drupal\Core\Url;
 | 
						|
use Drupal\user\Entity\User;
 | 
						|
use Drupal\user\UserInterface;
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns whether this site supports the default user picture feature.
 | 
						|
 *
 | 
						|
 * This approach preserves compatibility with node/comment templates. Alternate
 | 
						|
 * user picture implementations (e.g., Gravatar) should provide their own
 | 
						|
 * add/edit/delete forms and populate the 'picture' variable during the
 | 
						|
 * preprocess stage.
 | 
						|
 */
 | 
						|
function user_picture_enabled() {
 | 
						|
  $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('user', 'user');
 | 
						|
  return isset($field_definitions['user_picture']);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Fetches a user object by email address.
 | 
						|
 *
 | 
						|
 * @param string $mail
 | 
						|
 *   String with the account's email address.
 | 
						|
 *
 | 
						|
 * @return \Drupal\user\UserInterface|false
 | 
						|
 *   A fully-loaded $user object upon successful user load or FALSE if user
 | 
						|
 *   cannot be loaded.
 | 
						|
 *
 | 
						|
 * @see \Drupal\user\Entity\User::loadMultiple()
 | 
						|
 */
 | 
						|
function user_load_by_mail($mail) {
 | 
						|
  $users = \Drupal::entityTypeManager()->getStorage('user')
 | 
						|
    ->loadByProperties(['mail' => $mail]);
 | 
						|
  return $users ? reset($users) : FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Fetches a user object by account name.
 | 
						|
 *
 | 
						|
 * @param string $name
 | 
						|
 *   String with the account's user name.
 | 
						|
 *
 | 
						|
 * @return \Drupal\user\UserInterface|false
 | 
						|
 *   A fully-loaded $user object upon successful user load or FALSE if user
 | 
						|
 *   cannot be loaded.
 | 
						|
 *
 | 
						|
 * @see \Drupal\user\Entity\User::loadMultiple()
 | 
						|
 */
 | 
						|
function user_load_by_name($name) {
 | 
						|
  $users = \Drupal::entityTypeManager()->getStorage('user')
 | 
						|
    ->loadByProperties(['name' => $name]);
 | 
						|
  return $users ? reset($users) : FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Verify the syntax of the given name.
 | 
						|
 *
 | 
						|
 * @param string $name
 | 
						|
 *   The user name to validate.
 | 
						|
 *
 | 
						|
 * @return string|null
 | 
						|
 *   A translated violation message if the name is invalid or NULL if the name
 | 
						|
 *   is valid.
 | 
						|
 *
 | 
						|
 * @deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use
 | 
						|
 *   \Drupal\user\UserNameValidator::validateName() instead.
 | 
						|
 *
 | 
						|
 * @see https://www.drupal.org/node/3431205
 | 
						|
 */
 | 
						|
function user_validate_name($name) {
 | 
						|
  @trigger_error(__METHOD__ . '() is deprecated in drupal:10.3.0 and is removed from drupal:12.0.0. Use \Drupal\user\UserNameValidator::validateName() instead. See https://www.drupal.org/node/3431205', E_USER_DEPRECATED);
 | 
						|
  $violations = \Drupal::service('user.name_validator')->validateName($name);
 | 
						|
  if (count($violations) > 0) {
 | 
						|
    return $violations[0]->getMessage();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Checks for usernames blocked by user administration.
 | 
						|
 *
 | 
						|
 * @param string $name
 | 
						|
 *   A string containing a name of the user.
 | 
						|
 *
 | 
						|
 * @return bool
 | 
						|
 *   TRUE if the user is blocked, FALSE otherwise.
 | 
						|
 *
 | 
						|
 * @deprecated in drupal:11.0.0 and is removed from drupal:12.0.0. Use
 | 
						|
 * Drupal\user\UserInterface::isBlocked() instead.
 | 
						|
 * @see https://www.drupal.org/node/3411040
 | 
						|
 */
 | 
						|
function user_is_blocked($name) {
 | 
						|
  @trigger_error('user_is_blocked() is deprecated in drupal:11.0.0 and is removed from drupal:12.0.0. Use \Drupal\user\UserInterface::isBlocked() instead. See https://www.drupal.org/node/3411040', E_USER_DEPRECATED);
 | 
						|
  return (bool) \Drupal::entityQuery('user')
 | 
						|
    ->accessCheck(FALSE)
 | 
						|
    ->condition('name', $name)
 | 
						|
    ->condition('status', 0)
 | 
						|
    ->execute();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Implements hook_preprocess_HOOK() for block templates.
 | 
						|
 */
 | 
						|
function user_preprocess_block(&$variables): void {
 | 
						|
  if ($variables['configuration']['provider'] == 'user') {
 | 
						|
    switch ($variables['elements']['#plugin_id']) {
 | 
						|
      case 'user_login_block':
 | 
						|
        $variables['attributes']['role'] = 'form';
 | 
						|
        break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Prepares variables for username templates.
 | 
						|
 *
 | 
						|
 * Default template: username.html.twig.
 | 
						|
 *
 | 
						|
 * Modules that make any changes to variables like 'name' or 'extra' must ensure
 | 
						|
 * that the final string is safe.
 | 
						|
 *
 | 
						|
 * @param array $variables
 | 
						|
 *   An associative array containing:
 | 
						|
 *   - account: The user account (\Drupal\Core\Session\AccountInterface).
 | 
						|
 */
 | 
						|
function template_preprocess_username(&$variables): void {
 | 
						|
  $account = $variables['account'] ?: new AnonymousUserSession();
 | 
						|
 | 
						|
  $variables['extra'] = '';
 | 
						|
  $variables['uid'] = $account->id();
 | 
						|
  if (empty($variables['uid'])) {
 | 
						|
    if (theme_get_setting('features.comment_user_verification')) {
 | 
						|
      $variables['extra'] = ' (' . t('not verified') . ')';
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Set the name to a formatted name that is safe for printing and
 | 
						|
  // that won't break tables by being too long. Keep an un-shortened,
 | 
						|
  // unsanitized version, in case other preprocess functions want to implement
 | 
						|
  // their own shortening logic or add markup. If they do so, they must ensure
 | 
						|
  // that $variables['name'] is safe for printing.
 | 
						|
  $name = $account->getDisplayName();
 | 
						|
  $variables['name_raw'] = $account->getAccountName();
 | 
						|
  if (mb_strlen($name) > 20) {
 | 
						|
    $name = Unicode::truncate($name, 15, FALSE, TRUE);
 | 
						|
    $variables['truncated'] = TRUE;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    $variables['truncated'] = FALSE;
 | 
						|
  }
 | 
						|
  $variables['name'] = $name;
 | 
						|
  if ($account instanceof AccessibleInterface) {
 | 
						|
    $variables['profile_access'] = $account->access('view');
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    $variables['profile_access'] = \Drupal::currentUser()->hasPermission('access user profiles');
 | 
						|
  }
 | 
						|
 | 
						|
  $external = FALSE;
 | 
						|
  // Populate link path and attributes if appropriate.
 | 
						|
  if ($variables['uid'] && $variables['profile_access']) {
 | 
						|
    // We are linking to a local user.
 | 
						|
    $variables['attributes']['title'] = t('View user profile.');
 | 
						|
    $variables['link_path'] = 'user/' . $variables['uid'];
 | 
						|
  }
 | 
						|
  elseif (!empty($account->homepage)) {
 | 
						|
    // Like the 'class' attribute, the 'rel' attribute can hold a
 | 
						|
    // space-separated set of values, so initialize it as an array to make it
 | 
						|
    // easier for other preprocess functions to append to it.
 | 
						|
    $variables['attributes']['rel'] = 'nofollow';
 | 
						|
    $variables['link_path'] = $account->homepage;
 | 
						|
    $variables['homepage'] = $account->homepage;
 | 
						|
    $external = TRUE;
 | 
						|
  }
 | 
						|
  // We have a link path, so we should generate a URL.
 | 
						|
  if (isset($variables['link_path'])) {
 | 
						|
    if ($external) {
 | 
						|
      $variables['attributes']['href'] = Url::fromUri($variables['link_path'], $variables['link_options'])
 | 
						|
        ->toString();
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      $variables['attributes']['href'] = Url::fromRoute('entity.user.canonical', [
 | 
						|
        'user' => $variables['uid'],
 | 
						|
      ])->toString();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Finalizes the login process and logs in a user.
 | 
						|
 *
 | 
						|
 * The function logs in the user, records a watchdog message about the new
 | 
						|
 * session, saves the login timestamp, calls hook_user_login(), and generates a
 | 
						|
 * new session.
 | 
						|
 *
 | 
						|
 * The current user is replaced with the passed in account.
 | 
						|
 *
 | 
						|
 * @param \Drupal\user\UserInterface $account
 | 
						|
 *   The account to log in.
 | 
						|
 *
 | 
						|
 * @see hook_user_login()
 | 
						|
 * @see \Drupal\user\Authentication\Provider\Cookie
 | 
						|
 */
 | 
						|
function user_login_finalize(UserInterface $account): void {
 | 
						|
  \Drupal::currentUser()->setAccount($account);
 | 
						|
  \Drupal::logger('user')->info('Session opened for %name.', ['%name' => $account->getAccountName()]);
 | 
						|
  // Update the user table timestamp noting user has logged in.
 | 
						|
  // This is also used to invalidate one-time login links.
 | 
						|
  $account->setLastLoginTime(\Drupal::time()->getRequestTime());
 | 
						|
  \Drupal::entityTypeManager()
 | 
						|
    ->getStorage('user')
 | 
						|
    ->updateLastLoginTimestamp($account);
 | 
						|
 | 
						|
  // Regenerate the session ID to prevent against session fixation attacks.
 | 
						|
  // This is called before hook_user_login() in case one of those functions
 | 
						|
  // fails or incorrectly does a redirect which would leave the old session
 | 
						|
  // in place.
 | 
						|
  /** @var \Symfony\Component\HttpFoundation\Session\SessionInterface $session */
 | 
						|
  $session = \Drupal::service('session');
 | 
						|
  $session->migrate();
 | 
						|
  $session->set('uid', $account->id());
 | 
						|
  $session->set('check_logged_in', TRUE);
 | 
						|
  \Drupal::moduleHandler()->invokeAll('user_login', [$account]);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Generates a unique URL for a user to log in and reset their password.
 | 
						|
 *
 | 
						|
 * @param \Drupal\user\UserInterface $account
 | 
						|
 *   An object containing the user account.
 | 
						|
 * @param array $options
 | 
						|
 *   (optional) A keyed array of settings. Supported options are:
 | 
						|
 *   - langcode: A language code to be used when generating locale-sensitive
 | 
						|
 *    URLs. If langcode is NULL the users preferred language is used.
 | 
						|
 *
 | 
						|
 * @return string
 | 
						|
 *   A unique URL that provides a one-time log in for the user, from which
 | 
						|
 *   they can change their password.
 | 
						|
 */
 | 
						|
function user_pass_reset_url($account, $options = []) {
 | 
						|
  $timestamp = \Drupal::time()->getCurrentTime();
 | 
						|
  $langcode = $options['langcode'] ?? $account->getPreferredLangcode();
 | 
						|
  return Url::fromRoute('user.reset',
 | 
						|
    [
 | 
						|
      'uid' => $account->id(),
 | 
						|
      'timestamp' => $timestamp,
 | 
						|
      'hash' => user_pass_rehash($account, $timestamp),
 | 
						|
    ],
 | 
						|
    [
 | 
						|
      'absolute' => TRUE,
 | 
						|
      'language' => \Drupal::languageManager()->getLanguage($langcode),
 | 
						|
    ]
 | 
						|
  )->toString();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Generates a URL to confirm an account cancellation request.
 | 
						|
 *
 | 
						|
 * @param \Drupal\user\UserInterface $account
 | 
						|
 *   The user account object.
 | 
						|
 * @param array $options
 | 
						|
 *   (optional) A keyed array of settings. Supported options are:
 | 
						|
 *   - langcode: A language code to be used when generating locale-sensitive
 | 
						|
 *     URLs. If langcode is NULL the users preferred language is used.
 | 
						|
 *
 | 
						|
 * @return string
 | 
						|
 *   A unique URL that may be used to confirm the cancellation of the user
 | 
						|
 *   account.
 | 
						|
 *
 | 
						|
 * @see user_mail_tokens()
 | 
						|
 * @see \Drupal\user\Controller\UserController::confirmCancel()
 | 
						|
 */
 | 
						|
function user_cancel_url(UserInterface $account, $options = []) {
 | 
						|
  $timestamp = \Drupal::time()->getRequestTime();
 | 
						|
  $langcode = $options['langcode'] ?? $account->getPreferredLangcode();
 | 
						|
  $url_options = ['absolute' => TRUE, 'language' => \Drupal::languageManager()->getLanguage($langcode)];
 | 
						|
  return Url::fromRoute('user.cancel_confirm', [
 | 
						|
    'user' => $account->id(),
 | 
						|
    'timestamp' => $timestamp,
 | 
						|
    'hashed_pass' => user_pass_rehash($account, $timestamp),
 | 
						|
  ], $url_options)->toString();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates a unique hash value for use in time-dependent per-user URLs.
 | 
						|
 *
 | 
						|
 * This hash is normally used to build a unique and secure URL that is sent to
 | 
						|
 * the user by email for purposes such as resetting the user's password. In
 | 
						|
 * order to validate the URL, the same hash can be generated again, from the
 | 
						|
 * same information, and compared to the hash value from the URL. The hash
 | 
						|
 * contains the time stamp, the user's last login time, the numeric user ID,
 | 
						|
 * and the user's email address.
 | 
						|
 * For a usage example, see user_cancel_url() and
 | 
						|
 * \Drupal\user\Controller\UserController::confirmCancel().
 | 
						|
 *
 | 
						|
 * @param \Drupal\user\UserInterface $account
 | 
						|
 *   An object containing the user account.
 | 
						|
 * @param int $timestamp
 | 
						|
 *   A UNIX timestamp, typically \Drupal::time()->getRequestTime().
 | 
						|
 *
 | 
						|
 * @return string
 | 
						|
 *   A string that is safe for use in URLs and SQL statements.
 | 
						|
 */
 | 
						|
function user_pass_rehash(UserInterface $account, $timestamp) {
 | 
						|
  $data = $timestamp;
 | 
						|
  $data .= ':' . $account->getLastLoginTime();
 | 
						|
  $data .= ':' . $account->id();
 | 
						|
  $data .= ':' . $account->getEmail();
 | 
						|
  return Crypt::hmacBase64($data, Settings::getHashSalt() . $account->getPassword());
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Cancel a user account.
 | 
						|
 *
 | 
						|
 * Since the user cancellation process needs to be run in a batch, either
 | 
						|
 * Form API will invoke it, or batch_process() needs to be invoked after calling
 | 
						|
 * this function and should define the path to redirect to.
 | 
						|
 *
 | 
						|
 * @param array $edit
 | 
						|
 *   An array of submitted form values.
 | 
						|
 * @param int $uid
 | 
						|
 *   The user ID of the user account to cancel.
 | 
						|
 * @param string $method
 | 
						|
 *   The account cancellation method to use.
 | 
						|
 *
 | 
						|
 * @see _user_cancel()
 | 
						|
 */
 | 
						|
function user_cancel($edit, $uid, $method): void {
 | 
						|
  $account = User::load($uid);
 | 
						|
 | 
						|
  if (!$account) {
 | 
						|
    \Drupal::messenger()->addError(t('The user account %id does not exist.', ['%id' => $uid]));
 | 
						|
    \Drupal::logger('user')->error('Attempted to cancel non-existing user account: %id.', ['%id' => $uid]);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  // Initialize batch (to set title).
 | 
						|
  $batch_builder = (new BatchBuilder())
 | 
						|
    ->setTitle(t('Cancelling account'));
 | 
						|
  batch_set($batch_builder->toArray());
 | 
						|
 | 
						|
  // When the 'user_cancel_delete' method is used, user_delete() is called,
 | 
						|
  // which invokes hook_ENTITY_TYPE_predelete() and hook_ENTITY_TYPE_delete()
 | 
						|
  // for the user entity. Modules should use those hooks to respond to the
 | 
						|
  // account deletion.
 | 
						|
  if ($method != 'user_cancel_delete') {
 | 
						|
    // Allow modules to add further sets to this batch.
 | 
						|
    \Drupal::moduleHandler()->invokeAll('user_cancel', [$edit, $account, $method]);
 | 
						|
  }
 | 
						|
 | 
						|
  // Finish the batch and actually cancel the account.
 | 
						|
  $batch_builder = (new BatchBuilder())
 | 
						|
    ->setTitle(t('Cancelling user account'))
 | 
						|
    ->addOperation('_user_cancel', [$edit, $account, $method]);
 | 
						|
 | 
						|
  // After cancelling account, ensure that user is logged out.
 | 
						|
  if ($account->id() == \Drupal::currentUser()->id()) {
 | 
						|
    // Batch API stores data in the session, so use the finished operation to
 | 
						|
    // manipulate the current user's session id.
 | 
						|
    $batch_builder->setFinishCallback('_user_cancel_session_regenerate');
 | 
						|
  }
 | 
						|
 | 
						|
  batch_set($batch_builder->toArray());
 | 
						|
 | 
						|
  // Batch processing is either handled via Form API or has to be invoked
 | 
						|
  // manually.
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Implements callback_batch_operation().
 | 
						|
 *
 | 
						|
 * Last step for cancelling a user account.
 | 
						|
 *
 | 
						|
 * Since batch and session API require a valid user account, the actual
 | 
						|
 * cancellation of a user account needs to happen last.
 | 
						|
 *
 | 
						|
 * @param array $edit
 | 
						|
 *   An array of submitted form values.
 | 
						|
 * @param \Drupal\user\UserInterface $account
 | 
						|
 *   The user ID of the user account to cancel.
 | 
						|
 * @param string $method
 | 
						|
 *   The account cancellation method to use.
 | 
						|
 *
 | 
						|
 * @see user_cancel()
 | 
						|
 */
 | 
						|
function _user_cancel($edit, $account, $method): void {
 | 
						|
  $logger = \Drupal::logger('user');
 | 
						|
 | 
						|
  switch ($method) {
 | 
						|
    case 'user_cancel_block':
 | 
						|
    case 'user_cancel_block_unpublish':
 | 
						|
    default:
 | 
						|
      // Send account blocked notification if option was checked.
 | 
						|
      if (!empty($edit['user_cancel_notify'])) {
 | 
						|
        _user_mail_notify('status_blocked', $account);
 | 
						|
      }
 | 
						|
      $account->block();
 | 
						|
      $account->save();
 | 
						|
      \Drupal::messenger()->addStatus(t('Account %name has been disabled.', ['%name' => $account->getDisplayName()]));
 | 
						|
      $logger->notice('Blocked user: %name %email.', ['%name' => $account->getAccountName(), '%email' => '<' . $account->getEmail() . '>']);
 | 
						|
      break;
 | 
						|
 | 
						|
    case 'user_cancel_reassign':
 | 
						|
    case 'user_cancel_delete':
 | 
						|
      // Send account canceled notification if option was checked.
 | 
						|
      if (!empty($edit['user_cancel_notify'])) {
 | 
						|
        _user_mail_notify('status_canceled', $account);
 | 
						|
      }
 | 
						|
      $account->delete();
 | 
						|
      \Drupal::messenger()->addStatus(t('Account %name has been deleted.', ['%name' => $account->getDisplayName()]));
 | 
						|
      $logger->notice('Deleted user: %name %email.', ['%name' => $account->getAccountName(), '%email' => '<' . $account->getEmail() . '>']);
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  // After cancelling account, ensure that user is logged out. We can't destroy
 | 
						|
  // their session though, as we might have information in it, and we can't
 | 
						|
  // regenerate it because batch API uses the session ID, we will regenerate it
 | 
						|
  // in _user_cancel_session_regenerate().
 | 
						|
  if ($account->id() == \Drupal::currentUser()->id()) {
 | 
						|
    \Drupal::currentUser()->setAccount(new AnonymousUserSession());
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Implements callback_batch_finished().
 | 
						|
 *
 | 
						|
 * Finished batch processing callback for cancelling a user account.
 | 
						|
 *
 | 
						|
 * @see user_cancel()
 | 
						|
 */
 | 
						|
function _user_cancel_session_regenerate(): void {
 | 
						|
  // Regenerate the users session instead of calling session_destroy() as we
 | 
						|
  // want to preserve any messages that might have been set.
 | 
						|
  \Drupal::service('session')->migrate();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Helper function to return available account cancellation methods.
 | 
						|
 *
 | 
						|
 * See documentation of hook_user_cancel_methods_alter().
 | 
						|
 *
 | 
						|
 * @return array
 | 
						|
 *   An array containing all account cancellation methods as form elements.
 | 
						|
 *
 | 
						|
 * @see hook_user_cancel_methods_alter()
 | 
						|
 * @see user_admin_settings()
 | 
						|
 */
 | 
						|
function user_cancel_methods(): array {
 | 
						|
  $user_settings = \Drupal::config('user.settings');
 | 
						|
  $anonymous_name = $user_settings->get('anonymous');
 | 
						|
  $methods = [
 | 
						|
    'user_cancel_block' => [
 | 
						|
      'title' => t('Disable the account and keep its content.'),
 | 
						|
      'description' => t('Your account will be blocked and you will no longer be able to log in. All of your content will remain attributed to your username.'),
 | 
						|
    ],
 | 
						|
    'user_cancel_block_unpublish' => [
 | 
						|
      'title' => t('Disable the account and unpublish its content.'),
 | 
						|
      'description' => t('Your account will be blocked and you will no longer be able to log in. All of your content will be hidden from everyone but administrators.'),
 | 
						|
    ],
 | 
						|
    'user_cancel_reassign' => [
 | 
						|
      'title' => t('Delete the account and make its content belong to the %anonymous-name user. This action cannot be undone.', ['%anonymous-name' => $anonymous_name]),
 | 
						|
      'description' => t('Your account will be removed and all account information deleted. All of your content will be assigned to the %anonymous-name user.', ['%anonymous-name' => $anonymous_name]),
 | 
						|
    ],
 | 
						|
    'user_cancel_delete' => [
 | 
						|
      'title' => t('Delete the account and its content. This action cannot be undone.'),
 | 
						|
      'description' => t('Your account will be removed and all account information deleted. All of your content will also be deleted.'),
 | 
						|
      'access' => \Drupal::currentUser()->hasPermission('administer users'),
 | 
						|
    ],
 | 
						|
  ];
 | 
						|
  // Allow modules to customize account cancellation methods.
 | 
						|
  \Drupal::moduleHandler()->alter('user_cancel_methods', $methods);
 | 
						|
 | 
						|
  // Turn all methods into real form elements.
 | 
						|
  $form = [
 | 
						|
    '#options' => [],
 | 
						|
    '#default_value' => $user_settings->get('cancel_method'),
 | 
						|
  ];
 | 
						|
  foreach ($methods as $name => $method) {
 | 
						|
    $form['#options'][$name] = $method['title'];
 | 
						|
    // Add the description for the confirmation form. This description is never
 | 
						|
    // shown for the cancel method option, only on the confirmation form.
 | 
						|
    // Therefore, we use a custom #confirm_description property.
 | 
						|
    if (isset($method['description'])) {
 | 
						|
      $form[$name]['#confirm_description'] = $method['description'];
 | 
						|
    }
 | 
						|
    if (isset($method['access'])) {
 | 
						|
      $form[$name]['#access'] = $method['access'];
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return $form;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Token callback to add unsafe tokens for user mails.
 | 
						|
 *
 | 
						|
 * This function is used by \Drupal\Core\Utility\Token::replace() to set up
 | 
						|
 * some additional tokens that can be used in email messages generated by
 | 
						|
 * user_mail().
 | 
						|
 *
 | 
						|
 * @param array $replacements
 | 
						|
 *   An associative array variable containing mappings from token names to
 | 
						|
 *   values (for use with strtr()).
 | 
						|
 * @param array $data
 | 
						|
 *   An associative array of token replacement values. If the 'user' element
 | 
						|
 *   exists, it must contain a user account object with the following
 | 
						|
 *   properties:
 | 
						|
 *   - login: The UNIX timestamp of the user's last login.
 | 
						|
 *   - pass: The hashed account login password.
 | 
						|
 * @param array $options
 | 
						|
 *   A keyed array of settings and flags to control the token replacement
 | 
						|
 *   process. See \Drupal\Core\Utility\Token::replace().
 | 
						|
 */
 | 
						|
function user_mail_tokens(&$replacements, $data, $options): void {
 | 
						|
  if (isset($data['user'])) {
 | 
						|
    $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user'], $options);
 | 
						|
    $replacements['[user:cancel-url]'] = user_cancel_url($data['user'], $options);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Change permissions for a user role.
 | 
						|
 *
 | 
						|
 * This function may be used to grant and revoke multiple permissions at once.
 | 
						|
 * For example, when a form exposes checkboxes to configure permissions for a
 | 
						|
 * role, the form submit handler may directly pass the submitted values for the
 | 
						|
 * checkboxes form element to this function.
 | 
						|
 *
 | 
						|
 * @param mixed $rid
 | 
						|
 *   The ID of a user role to alter.
 | 
						|
 * @param array $permissions
 | 
						|
 *   (optional) An associative array, where the key holds the permission name
 | 
						|
 *   and the value determines whether to grant or revoke that permission. Any
 | 
						|
 *   value that evaluates to TRUE will cause the permission to be granted.
 | 
						|
 *   Any value that evaluates to FALSE will cause the permission to be
 | 
						|
 *   revoked.
 | 
						|
 *   @code
 | 
						|
 *     [
 | 
						|
 *       'administer nodes' => 0,                // Revoke 'administer nodes'
 | 
						|
 *       'administer blocks' => FALSE,           // Revoke 'administer blocks'
 | 
						|
 *       'access user profiles' => 1,            // Grant 'access user profiles'
 | 
						|
 *       'access content' => TRUE,               // Grant 'access content'
 | 
						|
 *       'access comments' => 'access comments', // Grant 'access comments'
 | 
						|
 *     ]
 | 
						|
 *   @endcode
 | 
						|
 *   Existing permissions are not changed, unless specified in $permissions.
 | 
						|
 *
 | 
						|
 * @see user_role_grant_permissions()
 | 
						|
 * @see user_role_revoke_permissions()
 | 
						|
 */
 | 
						|
function user_role_change_permissions($rid, array $permissions = []): void {
 | 
						|
  // Grant new permissions for the role.
 | 
						|
  $grant = array_filter($permissions);
 | 
						|
  if (!empty($grant)) {
 | 
						|
    user_role_grant_permissions($rid, array_keys($grant));
 | 
						|
  }
 | 
						|
  // Revoke permissions for the role.
 | 
						|
  $revoke = array_diff_assoc($permissions, $grant);
 | 
						|
  if (!empty($revoke)) {
 | 
						|
    user_role_revoke_permissions($rid, array_keys($revoke));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Grant permissions to a user role.
 | 
						|
 *
 | 
						|
 * @param mixed $rid
 | 
						|
 *   The ID of a user role to alter.
 | 
						|
 * @param array $permissions
 | 
						|
 *   (optional) A list of permission names to grant.
 | 
						|
 *
 | 
						|
 * @see user_role_change_permissions()
 | 
						|
 * @see user_role_revoke_permissions()
 | 
						|
 */
 | 
						|
function user_role_grant_permissions($rid, array $permissions = []): void {
 | 
						|
  // Grant new permissions for the role.
 | 
						|
  $role_storage = \Drupal::entityTypeManager()->getStorage('user_role');
 | 
						|
  if ($role = $role_storage->loadOverrideFree($rid)) {
 | 
						|
    foreach ($permissions as $permission) {
 | 
						|
      $role->grantPermission($permission);
 | 
						|
    }
 | 
						|
    $role->trustData()->save();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Revoke permissions from a user role.
 | 
						|
 *
 | 
						|
 * @param mixed $rid
 | 
						|
 *   The ID of a user role to alter.
 | 
						|
 * @param array $permissions
 | 
						|
 *   (optional) A list of permission names to revoke.
 | 
						|
 *
 | 
						|
 * @see user_role_change_permissions()
 | 
						|
 * @see user_role_grant_permissions()
 | 
						|
 */
 | 
						|
function user_role_revoke_permissions($rid, array $permissions = []): void {
 | 
						|
  // Revoke permissions for the role.
 | 
						|
  $role_storage = \Drupal::entityTypeManager()->getStorage('user_role');
 | 
						|
  $role = $role_storage->loadOverrideFree($rid);
 | 
						|
  foreach ($permissions as $permission) {
 | 
						|
    $role->revokePermission($permission);
 | 
						|
  }
 | 
						|
  $role->trustData()->save();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates and sends a notification email following a change to a user account.
 | 
						|
 *
 | 
						|
 * @param string $op
 | 
						|
 *   The operation being performed on the account. Possible values:
 | 
						|
 *   - 'register_admin_created': Welcome message for user created by the admin.
 | 
						|
 *   - 'register_no_approval_required': Welcome message when user
 | 
						|
 *     self-registers.
 | 
						|
 *   - 'register_pending_approval': Welcome message, user pending admin
 | 
						|
 *     approval.
 | 
						|
 *   - 'password_reset': Password recovery request.
 | 
						|
 *   - 'status_activated': Account activated.
 | 
						|
 *   - 'status_blocked': Account blocked.
 | 
						|
 *   - 'cancel_confirm': Account cancellation request.
 | 
						|
 *   - 'status_canceled': Account canceled.
 | 
						|
 * @param \Drupal\Core\Session\AccountInterface $account
 | 
						|
 *   The user object of the account being notified. Must contain at
 | 
						|
 *   least the fields 'uid', 'name', and 'mail'.
 | 
						|
 *
 | 
						|
 * @return array
 | 
						|
 *   An array containing various information about the message.
 | 
						|
 *   See \Drupal\Core\Mail\MailManagerInterface::mail() for details.
 | 
						|
 *
 | 
						|
 * @see user_mail_tokens()
 | 
						|
 */
 | 
						|
function _user_mail_notify($op, AccountInterface $account) {
 | 
						|
 | 
						|
  if (\Drupal::config('user.settings')->get('notify.' . $op)) {
 | 
						|
    $params['account'] = $account;
 | 
						|
    // Get the custom site notification email to use as the from email address
 | 
						|
    // if it has been set.
 | 
						|
    $site_mail = \Drupal::config('system.site')->get('mail_notification');
 | 
						|
    // If the custom site notification email has not been set, we use the site
 | 
						|
    // default for this.
 | 
						|
    if (empty($site_mail)) {
 | 
						|
      $site_mail = \Drupal::config('system.site')->get('mail');
 | 
						|
    }
 | 
						|
    if (empty($site_mail)) {
 | 
						|
      $site_mail = ini_get('sendmail_from');
 | 
						|
    }
 | 
						|
    $mail = \Drupal::service('plugin.manager.mail')->mail('user', $op, $account->getEmail(), $account->getPreferredLangcode(), $params, $site_mail);
 | 
						|
    if ($op == 'register_pending_approval') {
 | 
						|
      // If a user registered requiring admin approval, notify the admin, too.
 | 
						|
      // We use the site default language for this.
 | 
						|
      \Drupal::service('plugin.manager.mail')->mail('user', 'register_pending_approval_admin', $site_mail, \Drupal::languageManager()->getDefaultLanguage()->getId(), $params);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return empty($mail) ? NULL : $mail['result'];
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Form element process handler for client-side password validation.
 | 
						|
 *
 | 
						|
 * This #process handler is automatically invoked for 'password_confirm' form
 | 
						|
 * elements to add the JavaScript and string translations for dynamic password
 | 
						|
 * validation.
 | 
						|
 */
 | 
						|
function user_form_process_password_confirm($element) {
 | 
						|
  $password_settings = [
 | 
						|
    'confirmTitle' => t('Passwords match:'),
 | 
						|
    'confirmSuccess' => t('yes'),
 | 
						|
    'confirmFailure' => t('no'),
 | 
						|
    'showStrengthIndicator' => FALSE,
 | 
						|
  ];
 | 
						|
 | 
						|
  if (\Drupal::config('user.settings')->get('password_strength')) {
 | 
						|
    $password_settings['showStrengthIndicator'] = TRUE;
 | 
						|
    $password_settings += [
 | 
						|
      'strengthTitle' => t('Password strength:'),
 | 
						|
      'hasWeaknesses' => t('Recommendations to make your password stronger:'),
 | 
						|
      'tooShort' => t('Make it at least 12 characters'),
 | 
						|
      'addLowerCase' => t('Add lowercase letters'),
 | 
						|
      'addUpperCase' => t('Add uppercase letters'),
 | 
						|
      'addNumbers' => t('Add numbers'),
 | 
						|
      'addPunctuation' => t('Add punctuation'),
 | 
						|
      'sameAsUsername' => t('Make it different from your username'),
 | 
						|
      'weak' => t('Weak'),
 | 
						|
      'fair' => t('Fair'),
 | 
						|
      'good' => t('Good'),
 | 
						|
      'strong' => t('Strong'),
 | 
						|
      'username' => \Drupal::currentUser()->getAccountName(),
 | 
						|
    ];
 | 
						|
  }
 | 
						|
 | 
						|
  $element['#attached']['library'][] = 'user/drupal.user';
 | 
						|
  $element['#attached']['drupalSettings']['password'] = $password_settings;
 | 
						|
 | 
						|
  return $element;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Saves visitor information as a cookie so it can be reused.
 | 
						|
 *
 | 
						|
 * @param array $values
 | 
						|
 *   An array of key/value pairs to be saved into a cookie.
 | 
						|
 */
 | 
						|
function user_cookie_save(array $values): void {
 | 
						|
  $request_time = \Drupal::time()->getRequestTime();
 | 
						|
  foreach ($values as $field => $value) {
 | 
						|
    // Set cookie for 365 days.
 | 
						|
    setrawcookie('Drupal.visitor.' . $field, rawurlencode($value), $request_time + 31536000, '/');
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Delete a visitor information cookie.
 | 
						|
 *
 | 
						|
 * @param string $cookie_name
 | 
						|
 *   A cookie name such as 'homepage'.
 | 
						|
 */
 | 
						|
function user_cookie_delete($cookie_name): void {
 | 
						|
  setrawcookie('Drupal.visitor.' . $cookie_name, '', \Drupal::time()->getRequestTime() - 3600, '/');
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Logs the current user out.
 | 
						|
 */
 | 
						|
function user_logout(): void {
 | 
						|
  $user = \Drupal::currentUser();
 | 
						|
 | 
						|
  \Drupal::logger('user')->info('Session closed for %name.', ['%name' => $user->getAccountName()]);
 | 
						|
 | 
						|
  \Drupal::moduleHandler()->invokeAll('user_logout', [$user]);
 | 
						|
 | 
						|
  // Destroy the current session, and reset $user to the anonymous user.
 | 
						|
  // Note: In Symfony the session is intended to be destroyed with
 | 
						|
  // Session::invalidate(). Regrettably this method is currently broken and may
 | 
						|
  // lead to the creation of spurious session records in the database.
 | 
						|
  // @see https://github.com/symfony/symfony/issues/12375
 | 
						|
  \Drupal::service('session_manager')->destroy();
 | 
						|
  $user->setAccount(new AnonymousUserSession());
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Prepares variables for user templates.
 | 
						|
 *
 | 
						|
 * Default template: user.html.twig.
 | 
						|
 *
 | 
						|
 * @param array $variables
 | 
						|
 *   An associative array containing:
 | 
						|
 *   - elements: An associative array containing the user information and any
 | 
						|
 *     fields attached to the user. Properties used:
 | 
						|
 *     - #user: A \Drupal\user\Entity\User object. The user account of the
 | 
						|
 *       profile being viewed.
 | 
						|
 *   - attributes: HTML attributes for the containing element.
 | 
						|
 */
 | 
						|
function template_preprocess_user(&$variables): void {
 | 
						|
  $variables['user'] = $variables['elements']['#user'];
 | 
						|
  // Helpful $content variable for templates.
 | 
						|
  foreach (Element::children($variables['elements']) as $key) {
 | 
						|
    $variables['content'][$key] = $variables['elements'][$key];
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Additional submit handler for \Drupal\system\Form\RegionalForm.
 | 
						|
 */
 | 
						|
function user_form_system_regional_settings_submit($form, FormStateInterface $form_state): void {
 | 
						|
  \Drupal::configFactory()->getEditable('system.date')
 | 
						|
    ->set('timezone.user.configurable', $form_state->getValue('configurable_timezones'))
 | 
						|
    ->set('timezone.user.warn', $form_state->getValue('empty_timezone_message'))
 | 
						|
    ->set('timezone.user.default', $form_state->getValue('user_default_timezone'))
 | 
						|
    ->save();
 | 
						|
}
 |