updated core to 8.6.1 via composer

This commit is contained in:
2018-09-12 13:58:26 +02:00
parent a9a219f2ed
commit ea56b9fba3
4443 changed files with 112098 additions and 40708 deletions
+8 -8
View File
@@ -6,7 +6,7 @@ use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Entity\EntityConstraintViolationListInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageInterface;
@@ -31,8 +31,8 @@ abstract class AccountForm extends ContentEntityForm {
/**
* Constructs a new EntityForm object.
*
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
* The entity manager.
* @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
* The entity repository.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
@@ -40,8 +40,8 @@ abstract class AccountForm extends ContentEntityForm {
* @param \Drupal\Component\Datetime\TimeInterface $time
* The time service.
*/
public function __construct(EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) {
parent::__construct($entity_manager, $entity_type_bundle_info, $time);
public function __construct(EntityRepositoryInterface $entity_repository, LanguageManagerInterface $language_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) {
parent::__construct($entity_repository, $entity_type_bundle_info, $time);
$this->languageManager = $language_manager;
}
@@ -50,7 +50,7 @@ abstract class AccountForm extends ContentEntityForm {
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity.manager'),
$container->get('entity.repository'),
$container->get('language_manager'),
$container->get('entity_type.bundle.info'),
$container->get('datetime.time')
@@ -347,7 +347,7 @@ abstract class AccountForm extends ContentEntityForm {
'timezone',
'langcode',
'preferred_langcode',
'preferred_admin_langcode'
'preferred_admin_langcode',
], parent::getEditedFieldNames($form_state));
}
@@ -365,7 +365,7 @@ abstract class AccountForm extends ContentEntityForm {
'timezone',
'langcode',
'preferred_langcode',
'preferred_admin_langcode'
'preferred_admin_langcode',
];
foreach ($violations->getByFields($field_names) as $violation) {
list($field_name) = explode('.', $violation->getPropertyPath(), 2);
@@ -154,13 +154,13 @@ class AccountSettingsForm extends ConfigFormBase {
USER_REGISTER_ADMINISTRATORS_ONLY => $this->t('Administrators only'),
USER_REGISTER_VISITORS => $this->t('Visitors'),
USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL => $this->t('Visitors, but administrator approval is required'),
]
],
];
$form['registration_cancellation']['user_email_verification'] = [
'#type' => 'checkbox',
'#title' => $this->t('Require email verification when a visitor creates an account'),
'#default_value' => $config->get('verify_mail'),
'#description' => $this->t('New users will be required to validate their email address prior to logging into the site, and will be assigned a system-generated password. With this setting disabled, users will be logged in immediately upon registering, and may select their own passwords during registration.')
'#description' => $this->t('New users will be required to validate their email address prior to logging into the site, and will be assigned a system-generated password. With this setting disabled, users will be logged in immediately upon registering, and may select their own passwords during registration.'),
];
$form['registration_cancellation']['user_password_strength'] = [
'#type' => 'checkbox',
@@ -4,9 +4,8 @@ namespace Drupal\user\ContextProvider;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\ContextProviderInterface;
use Drupal\Core\Plugin\Context\EntityContext;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
@@ -56,7 +55,7 @@ class CurrentUserContext implements ContextProviderInterface {
$current_user->_skipProtectedUserFieldConstraint = TRUE;
}
$context = new Context(new ContextDefinition('entity:user', $this->t('Current user')), $current_user);
$context = EntityContext::fromEntity($current_user, $this->t('Current user'));
$cacheability = new CacheableMetadata();
$cacheability->setCacheContexts(['user']);
$context->addCacheableDependency($cacheability);
@@ -120,12 +120,17 @@ class UserController extends ControllerBase {
else {
/** @var \Drupal\user\UserInterface $reset_link_user */
if ($reset_link_user = $this->userStorage->load($uid)) {
drupal_set_message($this->t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please <a href=":logout">log out</a> and try using the link again.',
['%other_user' => $account->getUsername(), '%resetting_user' => $reset_link_user->getUsername(), ':logout' => $this->url('user.logout')]), 'warning');
$this->messenger()
->addWarning($this->t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please <a href=":logout">log out</a> and try using the link again.',
[
'%other_user' => $account->getUsername(),
'%resetting_user' => $reset_link_user->getUsername(),
':logout' => $this->url('user.logout'),
]));
}
else {
// Invalid one-time link specifies an unknown user.
drupal_set_message($this->t('The one-time login link you clicked is invalid.'), 'error');
$this->messenger()->addError($this->t('The one-time login link you clicked is invalid.'));
}
return $this->redirect('<front>');
}
@@ -218,13 +223,13 @@ class UserController extends ControllerBase {
$timeout = $this->config('user.settings')->get('password_reset_timeout');
// No time out for first time login.
if ($user->getLastLoginTime() && $current - $timestamp > $timeout) {
drupal_set_message($this->t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'error');
$this->messenger()->addError($this->t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
return $this->redirect('user.pass');
}
elseif ($user->isAuthenticated() && ($timestamp >= $user->getLastLoginTime()) && ($timestamp <= $current) && Crypt::hashEquals($hash, user_pass_rehash($user, $timestamp))) {
user_login_finalize($user);
$this->logger->notice('User %name used one-time login link at time %timestamp.', ['%name' => $user->getDisplayName(), '%timestamp' => $timestamp]);
drupal_set_message($this->t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
$this->messenger()->addStatus($this->t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
// Let the user's password be changed without the current password
// check.
$token = Crypt::randomBytesBase64(55);
@@ -239,7 +244,7 @@ class UserController extends ControllerBase {
);
}
drupal_set_message($this->t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'), 'error');
$this->messenger()->addError($this->t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'));
return $this->redirect('user.pass');
}
@@ -268,7 +273,7 @@ class UserController extends ControllerBase {
* NULL.
*/
public function userTitle(UserInterface $user = NULL) {
return $user ? ['#markup' => $user->getUsername(), '#allowed_tags' => Xss::getHtmlTagList()] : '';
return $user ? ['#markup' => $user->getDisplayName(), '#allowed_tags' => Xss::getHtmlTagList()] : '';
}
/**
@@ -312,10 +317,10 @@ class UserController extends ControllerBase {
// Since user_cancel() is not invoked via Form API, batch processing
// needs to be invoked manually and should redirect to the front page
// after completion.
return batch_process('');
return batch_process('<front>');
}
else {
drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'error');
$this->messenger()->addError($this->t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'));
return $this->redirect('entity.user.cancel_form', ['user' => $user->id()], ['absolute' => TRUE]);
}
}
+7
View File
@@ -12,6 +12,13 @@ use Drupal\user\RoleInterface;
* @ConfigEntityType(
* id = "user_role",
* label = @Translation("Role"),
* label_collection = @Translation("Roles"),
* label_singular = @Translation("role"),
* label_plural = @Translation("roles"),
* label_count = @PluralTranslation(
* singular = "@count role",
* plural = "@count roles",
* ),
* handlers = {
* "storage" = "Drupal\user\RoleStorage",
* "access" = "Drupal\user\RoleAccessControlHandler",
+9 -1
View File
@@ -22,6 +22,13 @@ use Drupal\user\UserInterface;
* @ContentEntityType(
* id = "user",
* label = @Translation("User"),
* label_collection = @Translation("Users"),
* label_singular = @Translation("user"),
* label_plural = @Translation("users"),
* label_count = @PluralTranslation(
* singular = "@count user",
* plural = "@count users",
* ),
* handlers = {
* "storage" = "Drupal\user\UserStorage",
* "storage_schema" = "Drupal\user\UserStorageSchema",
@@ -348,6 +355,7 @@ class User extends ContentEntityBase implements UserInterface {
public function isAuthenticated() {
return $this->id() > 0;
}
/**
* {@inheritdoc}
*/
@@ -420,7 +428,7 @@ class User extends ContentEntityBase implements UserInterface {
'name' => [LanguageInterface::LANGCODE_DEFAULT => ''],
// Explicitly set the langcode to ensure that field definitions do not
// need to be fetched to figure out a default.
'langcode' => [LanguageInterface::LANGCODE_DEFAULT => LanguageInterface::LANGCODE_NOT_SPECIFIED]
'langcode' => [LanguageInterface::LANGCODE_DEFAULT => LanguageInterface::LANGCODE_NOT_SPECIFIED],
], $entity_type->id());
}
return clone static::$anonymousUser;
@@ -139,7 +139,7 @@ class UserCancelForm extends ContentEntityConfirmFormBase {
$this->entity->user_cancel_notify = $form_state->getValue('user_cancel_notify');
$this->entity->save();
_user_mail_notify('cancel_confirm', $this->entity);
drupal_set_message($this->t('A confirmation request to cancel your account has been sent to your email address.'));
$this->messenger()->addStatus($this->t('A confirmation request to cancel your account has been sent to your email address.'));
$this->logger('user')->notice('Sent account cancellation request to %name %email.', ['%name' => $this->entity->label(), '%email' => '<' . $this->entity->getEmail() . '>']);
$form_state->setRedirect(
@@ -5,6 +5,7 @@ namespace Drupal\user\Form;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Url;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\user\UserStorageInterface;
@@ -132,7 +133,7 @@ class UserMultipleCancelConfirm extends ConfirmFormBase {
if (isset($root)) {
$redirect = (count($accounts) == 1);
$message = $this->t('The user account %name cannot be canceled.', ['%name' => $root->label()]);
drupal_set_message($message, $redirect ? 'error' : 'warning');
$this->messenger()->addMessage($message, $redirect ? MessengerInterface::TYPE_ERROR : MessengerInterface::TYPE_WARNING);
// If only user 1 was selected, redirect to the overview.
if ($redirect) {
return $this->redirect('entity.user.collection');
@@ -140,7 +140,7 @@ class UserPasswordForm extends FormBase {
$mail = _user_mail_notify('password_reset', $account, $langcode);
if (!empty($mail)) {
$this->logger('user')->notice('Password reset instructions mailed to %name at %email.', ['%name' => $account->getUsername(), '%email' => $account->getEmail()]);
drupal_set_message($this->t('Further instructions have been sent to your email address.'));
$this->messenger()->addStatus($this->t('Further instructions have been sent to your email address.'));
}
$form_state->setRedirect('user.page');
@@ -216,7 +216,7 @@ class UserPermissionsForm extends FormBase {
user_role_change_permissions($role_name, (array) $form_state->getValue($role_name));
}
drupal_set_message($this->t('The changes have been saved.'));
$this->messenger()->addStatus($this->t('The changes have been saved.'));
}
}
@@ -64,7 +64,6 @@ class UserLoginBlock extends BlockBase implements ContainerFactoryPluginInterfac
);
}
/**
* {@inheritdoc}
*/
@@ -2,7 +2,6 @@
namespace Drupal\user\Plugin\Validation\Constraint;
use Drupal\Component\Utility\Unicode;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
@@ -53,7 +52,7 @@ class UserNameConstraintValidator extends ConstraintValidator {
) {
$this->context->addViolation($constraint->illegalMessage);
}
if (Unicode::strlen($name) > USERNAME_MAX_LENGTH) {
if (mb_strlen($name) > USERNAME_MAX_LENGTH) {
$this->context->addViolation($constraint->tooLongMessage, ['%name' => $name, '%max' => USERNAME_MAX_LENGTH]);
}
}
@@ -3,6 +3,8 @@
namespace Drupal\user\Plugin\migrate;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\MigrateExecutable;
use Drupal\migrate\MigrateSkipRowException;
use Drupal\migrate\Plugin\Migration;
/**
@@ -31,11 +33,28 @@ class ProfileValues extends Migration {
$definition['idMap']['plugin'] = 'null';
try {
$profile_field_migration = $this->migrationPluginManager->createStubMigration($definition);
$migrate_executable = new MigrateExecutable($profile_field_migration);
$source_plugin = $profile_field_migration->getSourcePlugin();
$source_plugin->checkRequirements();
foreach ($source_plugin as $row) {
$name = $row->getSourceProperty('name');
$this->process[$name] = $name;
$fid = $row->getSourceProperty('fid');
// The user profile field name can be greater than 32 characters. Use
// the migrated profile field name in the process pipeline.
$configuration =
[
'migration' => 'user_profile_field',
'source_ids' => $fid,
];
$plugin = $this->processPluginManager->createInstance('migration_lookup', $configuration, $profile_field_migration);
$new_value = $plugin->transform($fid, $migrate_executable, $row, 'tmp');
if (isset($new_value[1])) {
// Set the destination to the migrated profile field name.
$this->process[$new_value[1]] = $name;
}
else {
throw new MigrateSkipRowException("Can't migrate source field $name.");
}
}
}
catch (RequirementsException $e) {
@@ -37,7 +37,7 @@ class User extends FieldMigration {
}
$info = $row->getSource();
$this->fieldPluginCache[$field_type]
->processFieldValues($this, $field_name, $info);
->defineValueProcessPipeline($this, $field_name, $info);
}
else {
if ($this->cckPluginManager->hasDefinition($field_type)) {
@@ -2,7 +2,6 @@
namespace Drupal\user\Plugin\migrate\destination;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityStorageInterface;
@@ -15,6 +14,52 @@ use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a destination plugin for migrating user entities.
*
* Example:
*
* The example below migrates users and preserves original passwords from a
* source that has passwords as MD5 hashes without salt. The passwords will be
* salted and re-hashed before they are saved to the destination Drupal
* database. The MD5 hash used in the example is a hash of 'password'.
*
* The example uses the EmbeddedDataSource source plugin for the sake of
* simplicity. The mapping between old user_ids and new Drupal uids is saved in
* the migration map table.
* @code
* id: custom_user_migration
* label: Custom user migration
* source:
* plugin: embedded_data
* data_rows:
* -
* user_id: 1
* name: johnsmith
* mail: johnsmith@example.com
* hash: '5f4dcc3b5aa765d61d8327deb882cf99'
* ids:
* user_id:
* type: integer
* process:
* name: name
* mail: mail
* pass: hash
* status:
* plugin: default_value
* default_value: 1
* destination:
* plugin: entity:user
* md5_passwords: true
* @endcode
*
* For configuration options inherited from the parent class, refer to
* \Drupal\migrate\Plugin\migrate\destination\EntityContentBase.
*
* The example above is about migrating an MD5 password hash. For more examples
* on different password hash types and a list of other user properties, refer
* to the handbook documentation:
* @see https://www.drupal.org/docs/8/api/migrate-api/migrate-destination-plugins-examples/migrating-users
*
* @MigrateDestination(
* id = "entity:user"
* )
@@ -122,8 +167,8 @@ class EntityUser extends EntityContentBase {
if (is_array($name)) {
$name = reset($name);
}
if (Unicode::strlen($name) > USERNAME_MAX_LENGTH) {
$row->setDestinationProperty('name', Unicode::substr($name, 0, USERNAME_MAX_LENGTH));
if (mb_strlen($name) > USERNAME_MAX_LENGTH) {
$row->setDestinationProperty('name', mb_substr($name, 0, USERNAME_MAX_LENGTH));
}
}
@@ -74,7 +74,7 @@ class UserLangcode extends ProcessPluginBase implements ContainerFactoryPluginIn
return 'en';
}
}
// If the user's language does not exists, use the default language.
// If the user's language does not exist, use the default language.
elseif ($this->languageManager->getLanguage($value) === NULL) {
return $this->languageManager->getDefaultLanguage()->getId();
}
@@ -54,6 +54,7 @@ class UserUpdate7002 extends ProcessPluginBase implements ContainerFactoryPlugin
$container->get('config.factory')->get('system.date')
);
}
/**
* {@inheritdoc}
*/
@@ -33,14 +33,6 @@ class User extends DrupalSqlBase {
// Add roles field.
$fields['roles'] = $this->t('Roles');
// Profile fields.
if ($this->moduleExists('profile')) {
$fields += $this->select('profile_fields', 'pf')
->fields('pf', ['name', 'title'])
->execute()
->fetchAllKeyed();
}
return $fields;
}
@@ -37,6 +37,7 @@ class UserPicture extends DrupalSqlBase {
'picture' => "Path to the user's uploaded picture.",
];
}
/**
* {@inheritdoc}
*/
@@ -68,6 +68,7 @@ class UserPictureFile extends DrupalSqlBase {
'filename' => 'The picture filename.',
];
}
/**
* {@inheritdoc}
*/
@@ -62,18 +62,32 @@ class User extends FieldableEntity {
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$uid = $row->getSourceProperty('uid');
$roles = $this->select('users_roles', 'ur')
->fields('ur', ['rid'])
->condition('ur.uid', $row->getSourceProperty('uid'))
->condition('ur.uid', $uid)
->execute()
->fetchCol();
$row->setSourceProperty('roles', $roles);
$row->setSourceProperty('data', unserialize($row->getSourceProperty('data')));
// If this entity was translated using Entity Translation, we need to get
// its source language to get the field values in the right language.
// The translations will be migrated by the d7_user_entity_translation
// migration.
$entity_translatable = $this->isEntityTranslatable('user');
$source_language = $this->getEntityTranslationSourceLanguage('user', $uid);
$language = $entity_translatable && $source_language ? $source_language : $row->getSourceProperty('language');
$row->setSourceProperty('entity_language', $language);
// Get Field API field values.
foreach (array_keys($this->getFields('user')) as $field) {
$row->setSourceProperty($field, $this->getFieldValues('user', $field, $row->getSourceProperty('uid')));
foreach ($this->getFields('user') as $field_name => $field) {
// Ensure we're using the right language if the entity and the field are
// translatable.
$field_language = $entity_translatable && $field['translatable'] ? $language : NULL;
$row->setSourceProperty($field_name, $this->getFieldValues('user', $field_name, $uid, NULL, $field_language));
}
// Get profile field values. This code is lifted directly from the D6
@@ -0,0 +1,79 @@
<?php
namespace Drupal\user\Plugin\migrate\source\d7;
use Drupal\migrate\Row;
use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;
/**
* Provides Drupal 7 user entity translations source plugin.
*
* @MigrateSource(
* id = "d7_user_entity_translation",
* source_module = "entity_translation"
* )
*/
class UserEntityTranslation extends FieldableEntity {
/**
* {@inheritdoc}
*/
public function query() {
$query = $this->select('entity_translation', 'et')
->fields('et')
->condition('et.entity_type', 'user')
->condition('et.source', '', '<>');
return $query;
}
/**
* {@inheritdoc}
*/
public function prepareRow(Row $row) {
$uid = $row->getSourceProperty('entity_id');
$language = $row->getSourceProperty('language');
// Get Field API field values.
foreach ($this->getFields('user') as $field_name => $field) {
// Ensure we're using the right language if the entity is translatable.
$field_language = $field['translatable'] ? $language : NULL;
$row->setSourceProperty($field_name, $this->getFieldValues('user', $field_name, $uid, NULL, $field_language));
}
return parent::prepareRow($row);
}
/**
* {@inheritdoc}
*/
public function fields() {
return [
'entity_type' => $this->t('The entity type this translation relates to'),
'entity_id' => $this->t('The entity id this translation relates to'),
'revision_id' => $this->t('The entity revision id this translation relates to'),
'language' => $this->t('The target language for this translation.'),
'source' => $this->t('The source language from which this translation was created.'),
'uid' => $this->t('The author of this translation.'),
'status' => $this->t('Boolean indicating whether the translation is published (visible to non-administrators).'),
'translate' => $this->t('A boolean indicating whether this translation needs to be updated.'),
'created' => $this->t('The Unix timestamp when the translation was created.'),
'changed' => $this->t('The Unix timestamp when the translation was most recently saved.'),
];
}
/**
* {@inheritdoc}
*/
public function getIds() {
return [
'entity_id' => [
'type' => 'integer',
],
'language' => [
'type' => 'string',
],
];
}
}
@@ -100,7 +100,6 @@ class Permission extends AccessPluginBase implements CacheableDependencyInterfac
return $this->t($this->options['perm']);
}
protected function defineOptions() {
$options = parent::defineOptions();
$options['perm'] = ['default' => 'access content'];
@@ -96,7 +96,6 @@ class Role extends AccessPluginBase implements CacheableDependencyInterface {
}
}
protected function defineOptions() {
$options = parent::defineOptions();
$options['role'] = ['default' => []];
@@ -23,7 +23,7 @@ class Uid extends NumericArgument {
protected $storage;
/**
* Constructs a Drupal\Component\Plugin\PluginBase object.
* Constructs a \Drupal\user\Plugin\views\argument\Uid object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
@@ -33,7 +33,7 @@ class Permissions extends PrerenderList {
protected $moduleHandler;
/**
* Constructs a Drupal\Component\Plugin\PluginBase object.
* Constructs a \Drupal\user\Plugin\views\field\Permissions object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
@@ -25,7 +25,7 @@ class Roles extends PrerenderList {
protected $database;
/**
* Constructs a Drupal\Component\Plugin\PluginBase object.
* Constructs a \Drupal\user\Plugin\views\field\Roles object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
@@ -82,7 +82,7 @@ class Roles extends PrerenderList {
$ordered_roles = array_flip(array_keys($roles));
foreach ($this->items as &$user_roles) {
// Create an array of rids that the user has in the role weight order.
$sorted_keys = array_intersect_key($ordered_roles, $user_roles);
$sorted_keys = array_intersect_key($ordered_roles, $user_roles);
// Merge with the unsorted array of role information which has the
// effect of sorting it.
$user_roles = array_merge($sorted_keys, $user_roles);
@@ -34,7 +34,6 @@ class UserData extends FieldPluginBase {
*/
protected $moduleHandler;
/**
* {@inheritdoc}
*/
@@ -37,7 +37,7 @@ class Users extends WizardPluginBase {
'plugin_id' => 'boolean',
'entity_type' => 'user',
'entity_field' => 'status',
]
],
];
/**
+1 -1
View File
@@ -38,7 +38,7 @@ class ProfileForm extends AccountForm {
$account->save();
$form_state->setValue('uid', $account->id());
drupal_set_message($this->t('The changes have been saved.'));
$this->messenger()->addStatus($this->t('The changes have been saved.'));
}
/**
+6 -6
View File
@@ -103,28 +103,28 @@ class RegisterForm extends AccountForm {
// New administrative account without notification.
if ($admin && !$notify) {
drupal_set_message($this->t('Created a new user account for <a href=":url">%name</a>. No email has been sent.', [':url' => $account->url(), '%name' => $account->getUsername()]));
$this->messenger()->addStatus($this->t('Created a new user account for <a href=":url">%name</a>. No email has been sent.', [':url' => $account->url(), '%name' => $account->getUsername()]));
}
// No email verification required; log in user immediately.
elseif (!$admin && !\Drupal::config('user.settings')->get('verify_mail') && $account->isActive()) {
_user_mail_notify('register_no_approval_required', $account);
user_login_finalize($account);
drupal_set_message($this->t('Registration successful. You are now logged in.'));
$this->messenger()->addStatus($this->t('Registration successful. You are now logged in.'));
$form_state->setRedirect('<front>');
}
// No administrator approval required.
elseif ($account->isActive() || $notify) {
if (!$account->getEmail() && $notify) {
drupal_set_message($this->t('The new user <a href=":url">%name</a> was created without an email address, so no welcome message was sent.', [':url' => $account->url(), '%name' => $account->getUsername()]));
$this->messenger()->addStatus($this->t('The new user <a href=":url">%name</a> was created without an email address, so no welcome message was sent.', [':url' => $account->url(), '%name' => $account->getUsername()]));
}
else {
$op = $notify ? 'register_admin_created' : 'register_no_approval_required';
if (_user_mail_notify($op, $account)) {
if ($notify) {
drupal_set_message($this->t('A welcome message with further instructions has been emailed to the new user <a href=":url">%name</a>.', [':url' => $account->url(), '%name' => $account->getUsername()]));
$this->messenger()->addStatus($this->t('A welcome message with further instructions has been emailed to the new user <a href=":url">%name</a>.', [':url' => $account->url(), '%name' => $account->getUsername()]));
}
else {
drupal_set_message($this->t('A welcome message with further instructions has been sent to your email address.'));
$this->messenger()->addStatus($this->t('A welcome message with further instructions has been sent to your email address.'));
$form_state->setRedirect('<front>');
}
}
@@ -133,7 +133,7 @@ class RegisterForm extends AccountForm {
// Administrator approval required.
else {
_user_mail_notify('register_pending_approval', $account);
drupal_set_message($this->t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, a welcome message with further instructions has been sent to your email address.'));
$this->messenger()->addStatus($this->t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, a welcome message with further instructions has been sent to your email address.'));
$form_state->setRedirect('<front>');
}
}
+2 -2
View File
@@ -57,11 +57,11 @@ class RoleForm extends EntityForm {
$edit_link = $this->entity->link($this->t('Edit'));
if ($status == SAVED_UPDATED) {
drupal_set_message($this->t('Role %label has been updated.', ['%label' => $entity->label()]));
$this->messenger()->addStatus($this->t('Role %label has been updated.', ['%label' => $entity->label()]));
$this->logger('user')->notice('Role %label has been updated.', ['%label' => $entity->label(), 'link' => $edit_link]);
}
else {
drupal_set_message($this->t('Role %label has been added.', ['%label' => $entity->label()]));
$this->messenger()->addStatus($this->t('Role %label has been added.', ['%label' => $entity->label()]));
$this->logger('user')->notice('Role %label has been added.', ['%label' => $entity->label(), 'link' => $edit_link]);
}
$form_state->setRedirect('entity.user_role.collection');
+40 -1
View File
@@ -4,7 +4,11 @@ namespace Drupal\user;
use Drupal\Core\Config\Entity\DraggableListBuilder;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a class to build a listing of user role entities.
@@ -13,6 +17,41 @@ use Drupal\Core\Form\FormStateInterface;
*/
class RoleListBuilder extends DraggableListBuilder {
/**
* The messenger.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* RoleListBuilder constructor.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entityType
* The entity type definition.
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
* The entity storage class.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger.
*/
public function __construct(EntityTypeInterface $entityType,
EntityStorageInterface $storage,
MessengerInterface $messenger) {
parent::__construct($entityType, $storage);
$this->messenger = $messenger;
}
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
return new static(
$entity_type,
$container->get('entity.manager')->getStorage($entity_type->id()),
$container->get('messenger')
);
}
/**
* {@inheritdoc}
*/
@@ -58,7 +97,7 @@ class RoleListBuilder extends DraggableListBuilder {
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
drupal_set_message(t('The role settings have been updated.'));
$this->messenger->addStatus($this->t('The role settings have been updated.'));
}
}
@@ -1,10 +1,11 @@
<?php
namespace Drupal\user\Tests;
namespace Drupal\user\Tests\Functional;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Test\AssertMailTrait;
use Drupal\Core\Url;
use Drupal\system\Tests\Cache\PageCacheTagsTestBase;
use Drupal\Tests\system\Functional\Cache\PageCacheTagsTestBase;
use Drupal\user\Entity\User;
/**
@@ -14,16 +15,9 @@ use Drupal\user\Entity\User;
*/
class UserPasswordResetTest extends PageCacheTagsTestBase {
/**
* The profile to install as a basis for testing.
*
* This test uses the standard profile to test the password reset in
* combination with an ajax request provided by the user picture configuration
* in the standard profile.
*
* @var string
*/
protected $profile = 'standard';
use AssertMailTrait {
getMails as drupalGetMails;
}
/**
* The user object to test password resetting.
@@ -54,7 +48,7 @@ class UserPasswordResetTest extends PageCacheTagsTestBase {
$this->drupalLogin($account);
$this->account = User::load($account->id());
$this->account->pass_raw = $account->pass_raw;
$this->account->passRaw = $account->passRaw;
$this->drupalLogout();
// Set the last login time that is used to generate the one-time link so
@@ -114,14 +108,6 @@ class UserPasswordResetTest extends PageCacheTagsTestBase {
$this->assertLink(t('Log out'));
$this->assertTitle(t('@name | @site', ['@name' => $this->account->getUsername(), '@site' => $this->config('system.site')->get('name')]), 'Logged in using password reset link.');
// Make sure the ajax request from uploading a user picture does not
// invalidate the reset token.
$image = current($this->drupalGetTestFiles('image'));
$edit = [
'files[user_picture_0]' => \Drupal::service('file_system')->realpath($image->uri),
];
$this->drupalPostAjaxForm(NULL, $edit, 'user_picture_0_upload_button');
// Change the forgotten password.
$password = user_password();
$edit = ['pass[pass1]' => $password, 'pass[pass2]' => $password];
@@ -0,0 +1,128 @@
<?php
namespace Drupal\user\Tests\FunctionalJavascript;
use Drupal\Core\Test\AssertMailTrait;
use Drupal\Core\Url;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
use Drupal\Tests\TestFileCreationTrait;
use Drupal\user\Entity\User;
/**
* Ensure that password reset methods work as expected.
*
* @group user
*/
class UserPasswordResetTest extends WebDriverTestBase {
use AssertMailTrait {
getMails as drupalGetMails;
}
use TestFileCreationTrait {
getTestFiles as drupalGetTestFiles;
}
/**
* The profile to install as a basis for testing.
*
* This test uses the standard profile to test the password reset in
* combination with an ajax request provided by the user picture configuration
* in the standard profile.
*
* @var string
*/
protected $profile = 'standard';
/**
* The user object to test password resetting.
*
* @var \Drupal\user\UserInterface
*/
protected $account;
/**
* {@inheritdoc}
*/
public static $modules = ['block'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Create a user.
$account = $this->drupalCreateUser();
// Activate user by logging in.
$this->drupalLogin($account);
$this->account = User::load($account->id());
$this->account->pass_raw = $account->pass_raw;
$this->drupalLogout();
// Set the last login time that is used to generate the one-time link so
// that it is definitely over a second ago.
$account->login = REQUEST_TIME - mt_rand(10, 100000);
db_update('users_field_data')
->fields(['login' => $account->getLastLoginTime()])
->condition('uid', $account->id())
->execute();
}
/**
* Tests password reset functionality with an AJAX form.
*
* Make sure the ajax request from uploading a user picture does not
* invalidate the reset token.
*/
public function testUserPasswordResetWithAdditionalAjaxForm() {
$this->drupalGet(Url::fromRoute('user.reset.form', ['uid' => $this->account->id()]));
// Try to reset the password for an invalid account.
$this->drupalGet('user/password');
// Reset the password by username via the password reset page.
$edit['name'] = $this->account->getUsername();
$this->drupalPostForm(NULL, $edit, t('Submit'));
$resetURL = $this->getResetURL();
$this->drupalGet($resetURL);
// Login
$this->drupalPostForm(NULL, NULL, t('Log in'));
// Generate file.
$image_file = current($this->drupalGetTestFiles('image'));
$image_path = \Drupal::service('file_system')->realpath($image_file->uri);
// Upload file.
$this->getSession()->getPage()->attachFileToField('Picture', $image_path);
$this->assertSession()->waitForButton('Remove');
// Change the forgotten password.
$password = user_password();
$edit = ['pass[pass1]' => $password, 'pass[pass2]' => $password];
$this->drupalPostForm(NULL, $edit, t('Save'));
// Verify that the password reset session has been destroyed.
$this->drupalPostForm(NULL, $edit, t('Save'));
// Password needed to make profile changes.
$this->assertSession()->pageTextContains("Your current password is missing or incorrect; it's required to change the Password.");
}
/**
* Retrieves password reset email and extracts the login link.
*/
public function getResetURL() {
// Assume the most recent email.
$_emails = $this->drupalGetMails();
$email = end($_emails);
$urls = [];
preg_match('#.+user/reset/.+#', $email['body'], $urls);
return $urls[0];
}
}
@@ -2,7 +2,7 @@
namespace Drupal\user\Tests;
use Drupal\system\Tests\System\SystemConfigFormTestBase;
use Drupal\KernelTests\ConfigFormTestBase;
use Drupal\user\AccountSettingsForm;
/**
@@ -10,8 +10,16 @@ use Drupal\user\AccountSettingsForm;
*
* @group user
*/
class UserAdminSettingsFormTest extends SystemConfigFormTestBase {
class UserAdminSettingsFormTest extends ConfigFormTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['user', 'system'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
@@ -121,38 +121,6 @@ class UserBlocksTest extends WebTestBase {
$this->assertNoText(t('Unrecognized username or password. Forgot your password?'));
}
/**
* Test the Who's Online block.
*/
public function testWhosOnlineBlock() {
$block = $this->drupalPlaceBlock('views_block:who_s_online-who_s_online_block');
// Generate users.
$user1 = $this->drupalCreateUser(['access user profiles']);
$user2 = $this->drupalCreateUser([]);
$user3 = $this->drupalCreateUser([]);
// Update access of two users to be within the active timespan.
$this->updateAccess($user1->id());
$this->updateAccess($user2->id(), REQUEST_TIME + 1);
// Insert an inactive user who should not be seen in the block, and ensure
// that the admin user used in setUp() does not appear.
$inactive_time = REQUEST_TIME - (15 * 60) - 1;
$this->updateAccess($user3->id(), $inactive_time);
$this->updateAccess($this->adminUser->id(), $inactive_time);
// Test block output.
\Drupal::currentUser()->setAccount($user1);
$content = entity_view($block, 'block');
$this->setRawContent(\Drupal::service('renderer')->renderRoot($content));
$this->assertRaw(t('2 users'), 'Correct number of online users (2 users).');
$this->assertText($user1->getUsername(), 'Active user 1 found in online list.');
$this->assertText($user2->getUsername(), 'Active user 2 found in online list.');
$this->assertNoText($user3->getUsername(), 'Inactive user not found in online list.');
$this->assertTrue(strpos($this->getRawContent(), $user1->getUsername()) > strpos($this->getRawContent(), $user2->getUsername()), 'Online users are ordered correctly.');
}
/**
* Updates the access column for a user.
*/
@@ -3,7 +3,7 @@
namespace Drupal\user\Tests;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
@@ -273,11 +273,11 @@ class UserRegistrationTest extends WebTestBase {
$edit = ['mail' => 'test@example.com', 'name' => $account->getUsername()];
$this->drupalPostForm('user/register', $edit, t('Create new account'));
$this->assertRaw(SafeMarkup::format('The username %value is already taken.', ['%value' => $account->getUsername()]));
$this->assertRaw(new FormattableMarkup('The username %value is already taken.', ['%value' => $account->getUsername()]));
$edit = ['mail' => $account->getEmail(), 'name' => $this->randomString()];
$this->drupalPostForm('user/register', $edit, t('Create new account'));
$this->assertRaw(SafeMarkup::format('The email address %value is already taken.', ['%value' => $account->getEmail()]));
$this->assertRaw(new FormattableMarkup('The email address %value is already taken.', ['%value' => $account->getEmail()]));
}
/**
@@ -348,35 +348,27 @@ class UserRegistrationTest extends WebTestBase {
// Check that the 'add more' button works.
$field_storage->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
$field_storage->save();
foreach (['js', 'nojs'] as $js) {
$this->drupalGet('user/register');
$this->assertRegistrationFormCacheTagsWithUserFields();
// Add two inputs.
$value = rand(1, 255);
$edit = [];
$edit['test_user_field[0][value]'] = $value;
if ($js == 'js') {
$this->drupalPostAjaxForm(NULL, $edit, 'test_user_field_add_more');
$this->drupalPostAjaxForm(NULL, $edit, 'test_user_field_add_more');
}
else {
$this->drupalPostForm(NULL, $edit, t('Add another item'));
$this->drupalPostForm(NULL, $edit, t('Add another item'));
}
// Submit with three values.
$edit['test_user_field[1][value]'] = $value + 1;
$edit['test_user_field[2][value]'] = $value + 2;
$edit['name'] = $name = $this->randomMachineName();
$edit['mail'] = $mail = $edit['name'] . '@example.com';
$this->drupalPostForm(NULL, $edit, t('Create new account'));
// Check user fields.
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
->loadByProperties(['name' => $name, 'mail' => $mail]);
$new_user = reset($accounts);
$this->assertEqual($new_user->test_user_field[0]->value, $value, format_string('@js : The field value was correctly saved.', ['@js' => $js]));
$this->assertEqual($new_user->test_user_field[1]->value, $value + 1, format_string('@js : The field value was correctly saved.', ['@js' => $js]));
$this->assertEqual($new_user->test_user_field[2]->value, $value + 2, format_string('@js : The field value was correctly saved.', ['@js' => $js]));
}
$this->drupalGet('user/register');
$this->assertRegistrationFormCacheTagsWithUserFields();
// Add two inputs.
$value = rand(1, 255);
$edit = [];
$edit['test_user_field[0][value]'] = $value;
$this->drupalPostForm(NULL, $edit, t('Add another item'));
$this->drupalPostForm(NULL, $edit, t('Add another item'));
// Submit with three values.
$edit['test_user_field[1][value]'] = $value + 1;
$edit['test_user_field[2][value]'] = $value + 2;
$edit['name'] = $name = $this->randomMachineName();
$edit['mail'] = $mail = $edit['name'] . '@example.com';
$this->drupalPostForm(NULL, $edit, t('Create new account'));
// Check user fields.
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
->loadByProperties(['name' => $name, 'mail' => $mail]);
$new_user = reset($accounts);
$this->assertEqual($new_user->test_user_field[0]->value, $value, 'The field value was correctly saved.');
$this->assertEqual($new_user->test_user_field[1]->value, $value + 1, 'The field value was correctly saved.');
$this->assertEqual($new_user->test_user_field[2]->value, $value + 2, 'The field value was correctly saved.');
}
/**
@@ -106,7 +106,7 @@ class UserAccessControlHandler extends EntityAccessControlHandler {
return AccessResult::allowed()->cachePerPermissions()->cachePerUser();
}
else {
return AccessResult::forbidden();
return AccessResult::neutral();
}
case 'preferred_langcode':
@@ -116,7 +116,7 @@ class UserAccessControlHandler extends EntityAccessControlHandler {
// Allow view access to own mail address and other personalization
// settings.
if ($operation == 'view') {
return $is_own_account ? AccessResult::allowed()->cachePerUser() : AccessResult::forbidden();
return $is_own_account ? AccessResult::allowed()->cachePerUser() : AccessResult::neutral();
}
// Anyone that can edit the user can also edit this field.
return AccessResult::allowed()->cachePerPermissions();
@@ -127,14 +127,14 @@ class UserAccessControlHandler extends EntityAccessControlHandler {
case 'created':
// Allow viewing the created date, but not editing it.
return ($operation == 'view') ? AccessResult::allowed() : AccessResult::forbidden();
return ($operation == 'view') ? AccessResult::allowed() : AccessResult::neutral();
case 'roles':
case 'status':
case 'access':
case 'login':
case 'init':
return AccessResult::forbidden();
return AccessResult::neutral();
}
return parent::checkFieldAccess($operation, $field_definition, $account, $items);
+3 -3
View File
@@ -21,7 +21,7 @@ class UserStorage extends SqlContentEntityStorage implements UserStorageInterfac
// The anonymous user account is saved with the fixed user ID of 0.
// Therefore we need to check for NULL explicitly.
if ($entity->id() === NULL) {
$entity->uid->value = $this->database->nextId($this->database->query('SELECT MAX(uid) FROM {users}')->fetchField());
$entity->uid->value = $this->database->nextId($this->database->query('SELECT MAX(uid) FROM {' . $this->getBaseTable() . '}')->fetchField());
$entity->enforceIsNew();
}
return parent::doSaveFieldItems($entity, $names);
@@ -39,7 +39,7 @@ class UserStorage extends SqlContentEntityStorage implements UserStorageInterfac
* {@inheritdoc}
*/
public function updateLastLoginTimestamp(UserInterface $account) {
$this->database->update('users_field_data')
$this->database->update($this->getDataTable())
->fields(['login' => $account->getLastLoginTime()])
->condition('uid', $account->id())
->execute();
@@ -51,7 +51,7 @@ class UserStorage extends SqlContentEntityStorage implements UserStorageInterfac
* {@inheritdoc}
*/
public function updateLastAccessTimestamp(AccountInterface $account, $timestamp) {
$this->database->update('users_field_data')
$this->database->update($this->getDataTable())
->fields([
'access' => $timestamp,
])
+5 -3
View File
@@ -17,9 +17,11 @@ class UserStorageSchema extends SqlContentEntityStorageSchema {
protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) {
$schema = parent::getEntitySchema($entity_type, $reset);
$schema['users_field_data']['unique keys'] += [
'user__name' => ['name', 'langcode'],
];
if ($data_table = $this->storage->getDataTable()) {
$schema[$data_table]['unique keys'] += [
'user__name' => ['name', 'langcode'],
];
}
return $schema;
}
+1 -1
View File
@@ -60,7 +60,7 @@ class UserViewsData extends EntityViewsData {
'argument field' => 'uid',
'base' => 'node_field_data',
'field' => 'nid',
'relationship' => 'node_field_data:uid'
'relationship' => 'node_field_data:uid',
],
];