updated core to 8.6.1 via composer
This commit is contained in:
@@ -11,7 +11,7 @@ register_no_approval_required:
|
||||
body: "[user:display-name],\n\nThank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it into your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, 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: 'Account details for [user:display-name] at [site:name]'
|
||||
register_pending_approval:
|
||||
body: "[user:display-name],\n\nThank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another email containing information about how to log in, set your password, and other details.\n\n\n-- [site:name] team"
|
||||
body: "[user:display-name],\n\nThank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another email containing information about how to log in, set your password, and other details.\n\n-- [site:name] team"
|
||||
subject: 'Account details for [user:display-name] at [site:name] (pending admin approval)'
|
||||
register_pending_approval_admin:
|
||||
body: "[user:display-name] has applied for an account.\n\n[user:edit-url]"
|
||||
|
||||
@@ -21,7 +21,7 @@ process:
|
||||
timezone: timezone
|
||||
langcode:
|
||||
plugin: user_langcode
|
||||
source: language
|
||||
source: entity_language
|
||||
fallback_to_site_default: false
|
||||
preferred_langcode:
|
||||
plugin: user_langcode
|
||||
|
||||
@@ -17,7 +17,18 @@ process:
|
||||
entity_type: 'constants/entity_type'
|
||||
bundle: 'constants/bundle'
|
||||
view_mode: 'constants/view_mode'
|
||||
field_name: name
|
||||
field_name:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: user_profile_field
|
||||
source: fid
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
-
|
||||
plugin: extract
|
||||
index:
|
||||
- 1
|
||||
type:
|
||||
plugin: static_map
|
||||
source: type
|
||||
|
||||
@@ -14,7 +14,18 @@ source:
|
||||
process:
|
||||
entity_type: 'constants/entity_type'
|
||||
bundle: 'constants/bundle'
|
||||
field_name: name
|
||||
field_name:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: user_profile_field
|
||||
source: fid
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
-
|
||||
plugin: extract
|
||||
index:
|
||||
- 1
|
||||
form_mode: 'constants/form_mode'
|
||||
type:
|
||||
plugin: static_map
|
||||
|
||||
@@ -10,7 +10,15 @@ source:
|
||||
entity_type: user
|
||||
process:
|
||||
entity_type: 'constants/entity_type'
|
||||
field_name: name
|
||||
field_name:
|
||||
-
|
||||
plugin: machine_name
|
||||
source: name
|
||||
-
|
||||
plugin: make_unique_entity_field
|
||||
length: 30
|
||||
entity_type: field_storage_config
|
||||
field: field_name
|
||||
type:
|
||||
plugin: static_map
|
||||
source: type
|
||||
|
||||
@@ -14,7 +14,18 @@ process:
|
||||
bundle: 'constants/bundle'
|
||||
label: title
|
||||
description: explanation
|
||||
field_name: name
|
||||
field_name:
|
||||
-
|
||||
plugin: migration_lookup
|
||||
migration: user_profile_field
|
||||
source: fid
|
||||
-
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
-
|
||||
plugin: extract
|
||||
index:
|
||||
- 1
|
||||
required: required
|
||||
destination:
|
||||
plugin: entity:field_config
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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',
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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.'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-21
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
])
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
+1
-1
@@ -18,5 +18,5 @@ $connection->insert('config')
|
||||
->values([
|
||||
'collection' => '',
|
||||
'name' => 'user.mail',
|
||||
'data' => "a:10:{s:14:\"cancel_confirm\";a:2:{s:4:\"body\";s:369:\"[user:name],\n\nA request to cancel your account has been made at [site:name].\n\nYou may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser:\n\n[user:cancel-url]\n\nNOTE: The cancellation of your account is not reversible.\n\nThis link expires in one day and nothing will happen if it is not used.\n\n-- [site:name] team\";s:7:\"subject\";s:59:\"Account cancellation request for [user:name] at [site:name]\";}s:14:\"password_reset\";a:2:{s:4:\"body\";s:397:\"[user:name],\n\nA request to reset the password for your account has been made at [site:name].\n\nYou may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used.\n\n-- [site:name] team\";s:7:\"subject\";s:60:\"Replacement login information for [user:name] at [site:name]\";}s:22:\"register_admin_created\";a:2:{s:4:\"body\";s:463:\"[user: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 to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, 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\";s:7:\"subject\";s:58:\"An administrator created an account for you at [site:name]\";}s:29:\"register_no_approval_required\";a:2:{s:4:\"body\";s:437:\"[user:name],\n\nThank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, 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\";s:7:\"subject\";s:46:\"Account details for [user:name] at [site:name]\";}s:25:\"register_pending_approval\";a:2:{s:4:\"body\";s:281:\"[user:name],\n\nThank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another email containing information about how to log in, set your password, and other details.\n\n\n-- [site:name] team\";s:7:\"subject\";s:71:\"Account details for [user:name] at [site:name] (pending admin approval)\";}s:31:\"register_pending_approval_admin\";a:2:{s:4:\"body\";s:56:\"[user:name] has applied for an account.\n\n[user:edit-url]\";s:7:\"subject\";s:71:\"Account details for [user:name] at [site:name] (pending admin approval)\";}s:16:\"status_activated\";a:2:{s:4:\"body\";s:446:\"[user:name],\n\nYour account at [site:name] has been activated.\n\nYou may now log in by clicking this link or copying and pasting it into your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, 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\";s:7:\"subject\";s:57:\"Account details for [user:name] at [site:name] (approved)\";}s:14:\"status_blocked\";a:2:{s:4:\"body\";s:89:\"[user:name],\n\nYour account on [site:account-name] has been blocked.\n\n-- [site:name] team\";s:7:\"subject\";s:56:\"Account details for [user:name] at [site:name] (blocked)\";}s:15:\"status_canceled\";a:2:{s:4:\"body\";s:82:\"[user:name],\n\nYour account on [site:name] has been canceled.\n\n-- [site:name] team\";s:7:\"subject\";s:57:\"Account details for [user:name] at [site:name] (canceled)\";}s:8:\"langcode\";s:2:\"en\";}"
|
||||
'data' => "a:10:{s:14:\"cancel_confirm\";a:2:{s:4:\"body\";s:369:\"[user:name],\n\nA request to cancel your account has been made at [site:name].\n\nYou may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser:\n\n[user:cancel-url]\n\nNOTE: The cancellation of your account is not reversible.\n\nThis link expires in one day and nothing will happen if it is not used.\n\n-- [site:name] team\";s:7:\"subject\";s:59:\"Account cancellation request for [user:name] at [site:name]\";}s:14:\"password_reset\";a:2:{s:4:\"body\";s:397:\"[user:name],\n\nA request to reset the password for your account has been made at [site:name].\n\nYou may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used.\n\n-- [site:name] team\";s:7:\"subject\";s:60:\"Replacement login information for [user:name] at [site:name]\";}s:22:\"register_admin_created\";a:2:{s:4:\"body\";s:463:\"[user: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 to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, 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\";s:7:\"subject\";s:58:\"An administrator created an account for you at [site:name]\";}s:29:\"register_no_approval_required\";a:2:{s:4:\"body\";s:437:\"[user:name],\n\nThank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, 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\";s:7:\"subject\";s:46:\"Account details for [user:name] at [site:name]\";}s:25:\"register_pending_approval\";a:2:{s:4:\"body\";s:281:\"[user:name],\n\nThank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another email containing information about how to log in, set your password, and other details.\n\n\n-- [site:name] team\";s:7:\"subject\";s:71:\"Account details for [user:name] at [site:name] (pending admin approval)\";}s:31:\"register_pending_approval_admin\";a:2:{s:4:\"body\";s:56:\"[user:name] has applied for an account.\n\n[user:edit-url]\";s:7:\"subject\";s:71:\"Account details for [user:name] at [site:name] (pending admin approval)\";}s:16:\"status_activated\";a:2:{s:4:\"body\";s:446:\"[user:name],\n\nYour account at [site:name] has been activated.\n\nYou may now log in by clicking this link or copying and pasting it into your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, 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\";s:7:\"subject\";s:57:\"Account details for [user:name] at [site:name] (approved)\";}s:14:\"status_blocked\";a:2:{s:4:\"body\";s:89:\"[user:name],\n\nYour account on [site:account-name] has been blocked.\n\n-- [site:name] team\";s:7:\"subject\";s:56:\"Account details for [user:name] at [site:name] (blocked)\";}s:15:\"status_canceled\";a:2:{s:4:\"body\";s:82:\"[user:name],\n\nYour account on [site:name] has been canceled.\n\n-- [site:name] team\";s:7:\"subject\";s:57:\"Account details for [user:name] at [site:name] (canceled)\";}s:8:\"langcode\";s:2:\"en\";}",
|
||||
])->execute();
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
*/
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
@@ -22,3 +25,16 @@ function user_access_test_user_access(User $entity, $operation, $account) {
|
||||
}
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_field_access().
|
||||
*/
|
||||
function user_access_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
|
||||
// Account with role sub-admin can view the status, init and mail fields for user with no roles.
|
||||
if ($operation === 'view' && in_array($field_definition->getName(), ['status', 'init', 'mail'])) {
|
||||
if (($items == NULL) || (count($items->getEntity()->getRoles()) == 1)) {
|
||||
return AccessResult::allowedIfHasPermission($account, 'sub-admin');
|
||||
}
|
||||
}
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
sub-admin:
|
||||
title: 'Administer users with no roles'
|
||||
@@ -4,4 +4,3 @@ user_form_test.cancel:
|
||||
_entity_form: 'user.cancel'
|
||||
requirements:
|
||||
_permission: 'cancel other accounts'
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Support module for user hooks testing.
|
||||
*/
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
|
||||
/**
|
||||
* Implements hook_user_format_name_alter().
|
||||
@@ -13,7 +13,7 @@ use Drupal\Component\Utility\SafeMarkup;
|
||||
function user_hooks_test_user_format_name_alter(&$name, $account) {
|
||||
if (\Drupal::state()->get('user_hooks_test_user_format_name_alter', FALSE)) {
|
||||
if (\Drupal::state()->get('user_hooks_test_user_format_name_alter_safe', FALSE)) {
|
||||
$name = SafeMarkup::format('<em>@uid</em>', ['@uid' => $account->id()]);
|
||||
$name = new FormattableMarkup('<em>@uid</em>', ['@uid' => $account->id()]);
|
||||
}
|
||||
else {
|
||||
$name = '<em>' . $account->id() . '</em>';
|
||||
|
||||
+478
@@ -0,0 +1,478 @@
|
||||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_user_fields_access
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
options: { }
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: mini
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: null
|
||||
expose:
|
||||
items_per_page: false
|
||||
items_per_page_label: 'Items per page'
|
||||
items_per_page_options: '5, 10, 25, 50'
|
||||
items_per_page_options_all: false
|
||||
items_per_page_options_all_label: '- All -'
|
||||
offset: false
|
||||
offset_label: Offset
|
||||
tags:
|
||||
previous: ‹‹
|
||||
next: ››
|
||||
style:
|
||||
type: table
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
override: true
|
||||
sticky: false
|
||||
caption: ''
|
||||
summary: ''
|
||||
description: ''
|
||||
columns:
|
||||
name: name
|
||||
status: status
|
||||
mail: mail
|
||||
init: init
|
||||
created: created
|
||||
info:
|
||||
name:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
status:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
mail:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
init:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
created:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
default: '-1'
|
||||
empty_table: false
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Name
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: user_name
|
||||
settings:
|
||||
link_to_entity: true
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
plugin_id: field
|
||||
status:
|
||||
id: status
|
||||
table: users_field_data
|
||||
field: status
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Status
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: boolean
|
||||
settings:
|
||||
format: default
|
||||
format_custom_true: ''
|
||||
format_custom_false: ''
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
plugin_id: field
|
||||
mail:
|
||||
id: mail
|
||||
table: users_field_data
|
||||
field: mail
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Email
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: basic_string
|
||||
settings: { }
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: mail
|
||||
plugin_id: field
|
||||
init:
|
||||
id: init
|
||||
table: users_field_data
|
||||
field: init
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Init
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: basic_string
|
||||
settings: { }
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: init
|
||||
plugin_id: field
|
||||
created:
|
||||
id: created
|
||||
table: users_field_data
|
||||
field: created
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Created
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: timestamp
|
||||
settings:
|
||||
date_format: medium
|
||||
custom_date_format: ''
|
||||
timezone: ''
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: created
|
||||
plugin_id: field
|
||||
filters: { }
|
||||
sorts: { }
|
||||
title: ''
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
tags: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: test_user_fields_access
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
tags: { }
|
||||
@@ -5,5 +5,5 @@ package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- user
|
||||
- views
|
||||
- drupal:user
|
||||
- drupal:views
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\user\Functional\Rest\RoleResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class RoleHalJsonAnonTest extends RoleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\user\Functional\Rest\RoleResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class RoleHalJsonBasicAuthTest extends RoleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal', 'basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\user\Functional\Rest\RoleResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class RoleHalJsonCookieTest extends RoleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\user\Functional\Rest\UserResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class UserHalJsonAnonTest extends UserResourceTestBase {
|
||||
|
||||
use HalEntityNormalizationTrait;
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$default_normalization = parent::getExpectedNormalizedEntity();
|
||||
|
||||
$normalization = $this->applyHalFieldNormalization($default_normalization);
|
||||
|
||||
return $normalization + [
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/user/3?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return parent::getNormalizedPostEntity() + [
|
||||
'_links' => [
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class UserHalJsonBasicAuthTest extends UserHalJsonAnonTest {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class UserHalJsonCookieTest extends UserHalJsonAnonTest {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleJsonAnonTest extends RoleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleJsonBasicAuthTest extends RoleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleJsonCookieTest extends RoleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
|
||||
abstract class RoleResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'user_role';
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\RoleInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer permissions']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$role = Role::create([
|
||||
'id' => 'llama',
|
||||
'name' => $this->randomString(),
|
||||
]);
|
||||
$role->save();
|
||||
|
||||
return $role;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'weight' => 2,
|
||||
'langcode' => 'en',
|
||||
'status' => TRUE,
|
||||
'dependencies' => [],
|
||||
'id' => 'llama',
|
||||
'label' => NULL,
|
||||
'is_admin' => NULL,
|
||||
'permissions' => [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleXmlAnonTest extends RoleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleXmlBasicAuthTest extends RoleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleXmlCookieTest extends RoleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserJsonAnonTest extends UserResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserJsonBasicAuthTest extends UserResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserJsonCookieTest extends UserResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
|
||||
abstract class UserResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
use BcTimestampNormalizerUnixTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'user';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'changed' => NULL,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $labelFieldName = 'name';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $firstCreatedEntityId = 4;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $secondCreatedEntityId = 5;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$this->grantPermissionsToTestedRole(['access user profiles']);
|
||||
break;
|
||||
case 'POST':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
$this->grantPermissionsToTestedRole(['administer users']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Llama" user.
|
||||
$user = User::create(['created' => 123456789]);
|
||||
$user->setUsername('Llama')
|
||||
->setChangedTime(123456789)
|
||||
->activate()
|
||||
->save();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createAnotherEntity() {
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = $this->entity->createDuplicate();
|
||||
$user->setUsername($user->label() . '_dupe');
|
||||
$user->save();
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'uid' => [
|
||||
['value' => 3],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $this->entity->uuid()],
|
||||
],
|
||||
'langcode' => [
|
||||
[
|
||||
'value' => 'en',
|
||||
],
|
||||
],
|
||||
'name' => [
|
||||
[
|
||||
'value' => 'Llama',
|
||||
],
|
||||
],
|
||||
'created' => [
|
||||
$this->formatExpectedTimestampItemValues(123456789),
|
||||
],
|
||||
'changed' => [
|
||||
$this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
|
||||
],
|
||||
'default_langcode' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return [
|
||||
'name' => [
|
||||
[
|
||||
'value' => 'Dramallama',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests PATCHing security-sensitive base fields of the logged in account.
|
||||
*/
|
||||
public function testPatchDxForSecuritySensitiveBaseFields() {
|
||||
// The anonymous user is never allowed to modify itself.
|
||||
if (!static::$auth) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
$this->initAuthentication();
|
||||
$this->provisionEntityResource();
|
||||
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = static::$auth ? $this->account : User::load(0);
|
||||
// @todo Remove the array_diff_key() call in https://www.drupal.org/node/2821077.
|
||||
$original_normalization = array_diff_key($this->serializer->normalize($user, static::$format), ['created' => TRUE, 'changed' => TRUE, 'name' => TRUE]);
|
||||
|
||||
// Since this test must be performed by the user that is being modified,
|
||||
// we cannot use $this->getUrl().
|
||||
$url = $user->toUrl()->setOption('query', ['_format' => static::$format]);
|
||||
$request_options = [
|
||||
RequestOptions::HEADERS => ['Content-Type' => static::$mimeType],
|
||||
];
|
||||
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
|
||||
// Test case 1: changing email.
|
||||
$normalization = $original_normalization;
|
||||
$normalization['mail'] = [['value' => 'new-email@example.com']];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// DX: 422 when changing email without providing the password.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response, FALSE, FALSE, FALSE, FALSE);
|
||||
|
||||
$normalization['pass'] = [['existing' => 'wrong']];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// DX: 422 when changing email while providing a wrong password.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response, FALSE, FALSE, FALSE, FALSE);
|
||||
|
||||
$normalization['pass'] = [['existing' => $this->account->passRaw]];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// 200 for well-formed request.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
// Test case 2: changing password.
|
||||
$normalization = $original_normalization;
|
||||
$new_password = $this->randomString();
|
||||
$normalization['pass'] = [['value' => $new_password]];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// DX: 422 when changing password without providing the current password.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\npass: Your current password is missing or incorrect; it's required to change the Password.\n", $response, FALSE, FALSE, FALSE, FALSE);
|
||||
|
||||
$normalization['pass'][0]['existing'] = $this->account->pass_raw;
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// 200 for well-formed request.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
// Verify that we can log in with the new password.
|
||||
$this->assertRpcLogin($user->getAccountName(), $new_password);
|
||||
|
||||
// Update password in $this->account, prepare for future requests.
|
||||
$this->account->passRaw = $new_password;
|
||||
$this->initAuthentication();
|
||||
$request_options = [
|
||||
RequestOptions::HEADERS => ['Content-Type' => static::$mimeType],
|
||||
];
|
||||
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
|
||||
// Test case 3: changing name.
|
||||
$normalization = $original_normalization;
|
||||
$normalization['name'] = [['value' => 'Cooler Llama']];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// DX: 403 when modifying username without required permission.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field 'name'.", $response);
|
||||
|
||||
$this->grantPermissionsToTestedRole(['change own username']);
|
||||
|
||||
// 200 for well-formed request.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
// Verify that we can log in with the new username.
|
||||
$this->assertRpcLogin('Cooler Llama', $new_password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that logging in with the given username and password works.
|
||||
*
|
||||
* @param string $username
|
||||
* The username to log in with.
|
||||
* @param string $password
|
||||
* The password to log in with.
|
||||
*/
|
||||
protected function assertRpcLogin($username, $password) {
|
||||
$request_body = [
|
||||
'name' => $username,
|
||||
'pass' => $password,
|
||||
];
|
||||
$request_options = [
|
||||
RequestOptions::HEADERS => [],
|
||||
RequestOptions::BODY => $this->serializer->encode($request_body, 'json'),
|
||||
];
|
||||
$response = $this->request('POST', Url::fromRoute('user.login.http')->setRouteParameter('_format', 'json'), $request_options);
|
||||
$this->assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests PATCHing security-sensitive base fields to change other users.
|
||||
*/
|
||||
public function testPatchSecurityOtherUser() {
|
||||
// The anonymous user is never allowed to modify other users.
|
||||
if (!static::$auth) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
$this->initAuthentication();
|
||||
$this->provisionEntityResource();
|
||||
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = $this->account;
|
||||
$original_normalization = array_diff_key($this->serializer->normalize($user, static::$format), ['changed' => TRUE]);
|
||||
|
||||
// Since this test must be performed by the user that is being modified,
|
||||
// we cannot use $this->getUrl().
|
||||
$url = $user->toUrl()->setOption('query', ['_format' => static::$format]);
|
||||
$request_options = [
|
||||
RequestOptions::HEADERS => ['Content-Type' => static::$mimeType],
|
||||
];
|
||||
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
|
||||
$normalization = $original_normalization;
|
||||
$normalization['mail'] = [['value' => 'new-email@example.com']];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// Try changing user 1's email.
|
||||
$user1 = [
|
||||
'mail' => [['value' => 'another_email_address@example.com']],
|
||||
'uid' => [['value' => 1]],
|
||||
'name' => [['value' => 'another_user_name']],
|
||||
'pass' => [['existing' => $this->account->passRaw]],
|
||||
'uuid' => [['value' => '2e9403a4-d8af-4096-a116-624710140be0']],
|
||||
] + $original_normalization;
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($user1, static::$format);
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
// Ensure the email address has not changed.
|
||||
$this->assertEquals('admin@example.com', $this->entityStorage->loadUnchanged(1)->getEmail());
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field 'uid'. The entity ID cannot be changed.", $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
return "The 'access user profiles' permission is required and the user must be active.";
|
||||
case 'PATCH':
|
||||
return "You are not authorized to update this user entity.";
|
||||
case 'DELETE':
|
||||
return 'You are not authorized to delete this user entity.';
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessCacheability() {
|
||||
// @see \Drupal\user\UserAccessControlHandler::checkAccess()
|
||||
return parent::getExpectedUnauthorizedAccessCacheability()
|
||||
->addCacheTags(['user:3']);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserXmlAnonTest extends UserResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchDxForSecuritySensitiveBaseFields() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserXmlBasicAuthTest extends UserResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchDxForSecuritySensitiveBaseFields() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchSecurityOtherUser() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserXmlCookieTest extends UserResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchDxForSecuritySensitiveBaseFields() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchSecurityOtherUser() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@ use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
* Tests user email token upgrade path.
|
||||
*
|
||||
* @group Update
|
||||
* @group legacy
|
||||
*/
|
||||
class UserUpdateEmailToken extends UpdatePathTestBase {
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
namespace Drupal\Tests\user\Functional\Update;
|
||||
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
|
||||
/**
|
||||
* Tests user permissions sort upgrade path.
|
||||
*
|
||||
* @group Update
|
||||
* @group legacy
|
||||
*/
|
||||
class UserUpdateOrderPermissionsTest extends UpdatePathTestBase {
|
||||
|
||||
@@ -25,14 +25,14 @@ class UserUpdateOrderPermissionsTest extends UpdatePathTestBase {
|
||||
* Tests that permissions are ordered by machine name.
|
||||
*/
|
||||
public function testPermissionsOrder() {
|
||||
$authenticated = Role::load('authenticated');
|
||||
$permissions = $authenticated->getPermissions();
|
||||
$authenticated = \Drupal::config('user.role.authenticated');
|
||||
$permissions = $authenticated->get('permissions');
|
||||
sort($permissions);
|
||||
$this->assertNotIdentical($permissions, $authenticated->getPermissions());
|
||||
$this->assertNotSame($permissions, $authenticated->get('permissions'));
|
||||
|
||||
$this->runUpdates();
|
||||
$authenticated = Role::load('authenticated');
|
||||
$this->assertIdentical($permissions, $authenticated->getPermissions());
|
||||
$authenticated = \Drupal::config('user.role.authenticated');
|
||||
$this->assertSame($permissions, $authenticated->get('permissions'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ class UserAdminTest extends BrowserTestBase {
|
||||
$this->drupalPostForm('admin/people', $edit, t('Apply to selected items'), [
|
||||
// Sort the table by username so that we know reliably which user will be
|
||||
// targeted with the blocking action.
|
||||
'query' => ['order' => 'name', 'sort' => 'asc']
|
||||
'query' => ['order' => 'name', 'sort' => 'asc'],
|
||||
]);
|
||||
$site_name = $this->config('system.site')->get('name');
|
||||
$this->assertMailString('body', 'Your account on ' . $site_name . ' has been blocked.', 1, 'Blocked message found in the mail sent to user C.');
|
||||
@@ -129,7 +129,7 @@ class UserAdminTest extends BrowserTestBase {
|
||||
$this->drupalPostForm('admin/people', $editunblock, t('Apply to selected items'), [
|
||||
// Sort the table by username so that we know reliably which user will be
|
||||
// targeted with the blocking action.
|
||||
'query' => ['order' => 'name', 'sort' => 'asc']
|
||||
'query' => ['order' => 'name', 'sort' => 'asc'],
|
||||
]);
|
||||
$user_storage->resetCache([$user_c->id()]);
|
||||
$account = $user_storage->load($user_c->id());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase;
|
||||
use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
@@ -99,23 +99,6 @@ class UserCancelTest extends BrowserTestBase {
|
||||
|
||||
\Drupal::service('module_installer')->install(['views']);
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
// Update uid 1's name and password to we know it.
|
||||
$password = user_password();
|
||||
$account = [
|
||||
'name' => 'user1',
|
||||
'pass' => $this->container->get('password')->hash(trim($password)),
|
||||
];
|
||||
// We cannot use $account->save() here, because this would result in the
|
||||
// password being hashed again.
|
||||
db_update('users_field_data')
|
||||
->fields($account)
|
||||
->condition('uid', 1)
|
||||
->execute();
|
||||
|
||||
// Reload and log in uid 1.
|
||||
$user_storage->resetCache([1]);
|
||||
$user1 = $user_storage->load(1);
|
||||
$user1->pass_raw = $password;
|
||||
|
||||
// Try to cancel uid 1's account with a different user.
|
||||
$admin_user = $this->drupalCreateUser(['administer users']);
|
||||
@@ -268,6 +251,12 @@ class UserCancelTest extends BrowserTestBase {
|
||||
|
||||
// Confirm account cancellation request.
|
||||
$this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
|
||||
// Confirm that the user was redirected to the front page.
|
||||
$this->assertSession()->addressEquals('');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
// Confirm that the confirmation message made it through to the end user.
|
||||
$this->assertRaw(t('%name has been disabled.', ['%name' => $account->getUsername()]), "Confirmation message displayed to user.");
|
||||
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
$this->assertTrue($account->isBlocked(), 'User has been blocked.');
|
||||
@@ -283,9 +272,6 @@ class UserCancelTest extends BrowserTestBase {
|
||||
$storage->resetCache([$comment->id()]);
|
||||
$comment = $storage->load($comment->id());
|
||||
$this->assertFalse($comment->isPublished(), 'Comment of the user has been unpublished.');
|
||||
|
||||
// Confirm that the confirmation message made it through to the end user.
|
||||
$this->assertRaw(t('%name has been disabled.', ['%name' => $account->getUsername()]), "Confirmation message displayed to user.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
@@ -29,9 +30,15 @@ class UserEditTest extends BrowserTestBase {
|
||||
// is the raw value and not a formatted one.
|
||||
\Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE);
|
||||
\Drupal::service('module_installer')->install(['user_hooks_test']);
|
||||
Cache::invalidateTags(['rendered']);
|
||||
$this->drupalGet('user/' . $user1->id() . '/edit');
|
||||
$this->assertFieldByName('name', $user1->getAccountName());
|
||||
|
||||
// Ensure the formatted name is displayed when expected.
|
||||
$this->drupalGet('user/' . $user1->id());
|
||||
$this->assertSession()->responseContains($user1->getDisplayName());
|
||||
$this->assertSession()->titleEquals(strip_tags($user1->getDisplayName()) . ' | Drupal');
|
||||
|
||||
// Check that filling out a single password field does not validate.
|
||||
$edit = [];
|
||||
$edit['pass[pass1]'] = '';
|
||||
|
||||
@@ -30,7 +30,7 @@ class UserMailNotifyTest extends EntityKernelTestBase {
|
||||
['status_canceled', ['status_canceled']],
|
||||
['register_admin_created', ['register_admin_created']],
|
||||
['register_no_approval_required', ['register_no_approval_required']],
|
||||
['register_pending_approval', ['register_pending_approval', 'register_pending_approval_admin']]
|
||||
['register_pending_approval', ['register_pending_approval', 'register_pending_approval_admin']],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -75,4 +75,25 @@ class UserTranslationUITest extends ContentTranslationUITestBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test translated user deletion.
|
||||
*/
|
||||
public function testTranslatedUserDeletion() {
|
||||
$this->drupalLogin($this->administrator);
|
||||
$entity_id = $this->createEntity($this->getNewEntityValues('en'), 'en');
|
||||
|
||||
$entity = $this->container->get('entity_type.manager')
|
||||
->getStorage($this->entityTypeId)
|
||||
->load($entity_id);
|
||||
$translated_entity = $entity->addTranslation('fr');
|
||||
$translated_entity->save();
|
||||
|
||||
$url = $entity->toUrl(
|
||||
'edit-form',
|
||||
['language' => $this->container->get('language_manager')->getLanguage('en')]
|
||||
);
|
||||
$this->drupalPostForm($url, [], t('Cancel account'));
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Views;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ class BulkFormAccessTest extends UserTestBase {
|
||||
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply to selected items'));
|
||||
$this->assertResponse(200);
|
||||
|
||||
$this->assertRaw(SafeMarkup::format('No access to execute %action on the @entity_type_label %entity_label.', [
|
||||
$this->assertRaw(new FormattableMarkup('No access to execute %action on the @entity_type_label %entity_label.', [
|
||||
'%action' => 'Block the selected user(s)',
|
||||
'@entity_type_label' => 'User',
|
||||
'%entity_label' => $no_edit_user->label(),
|
||||
|
||||
@@ -66,7 +66,6 @@ class HandlerFilterUserNameTest extends ViewTestBase {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests just using the filter.
|
||||
*/
|
||||
@@ -96,7 +95,7 @@ class HandlerFilterUserNameTest extends ViewTestBase {
|
||||
$users = [$this->randomMachineName()];
|
||||
$users = array_map('strtolower', $users);
|
||||
$edit = [
|
||||
'options[value]' => implode(', ', $users)
|
||||
'options[value]' => implode(', ', $users),
|
||||
];
|
||||
$this->drupalPostForm($path, $edit, t('Apply'));
|
||||
$this->assertRaw(t('There are no entities matching "%value".', ['%value' => implode(', ', $users)]));
|
||||
@@ -106,7 +105,7 @@ class HandlerFilterUserNameTest extends ViewTestBase {
|
||||
$users = [$random_name, $this->names[0]];
|
||||
$users = array_map('strtolower', $users);
|
||||
$edit = [
|
||||
'options[value]' => implode(', ', $users)
|
||||
'options[value]' => implode(', ', $users),
|
||||
];
|
||||
$users = [$users[0]];
|
||||
$this->drupalPostForm($path, $edit, t('Apply'));
|
||||
@@ -116,7 +115,7 @@ class HandlerFilterUserNameTest extends ViewTestBase {
|
||||
$users = $this->names;
|
||||
$users = array_map('strtolower', $users);
|
||||
$edit = [
|
||||
'options[value]' => implode(', ', $users)
|
||||
'options[value]' => implode(', ', $users),
|
||||
];
|
||||
$this->drupalPostForm($path, $edit, t('Apply'));
|
||||
$this->assertNoRaw(t('There are no entities matching "%value".', ['%value' => implode(', ', $users)]));
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Views;
|
||||
|
||||
/**
|
||||
* Checks if user fields access permissions can be modified by other modules.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserFieldsAccessChangeTest extends UserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['user_access_test'];
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_user_fields_access'];
|
||||
|
||||
/**
|
||||
* Tests if another module can change field access.
|
||||
*/
|
||||
public function testUserFieldAccess() {
|
||||
$path = 'test_user_fields_access';
|
||||
$this->drupalGet($path);
|
||||
|
||||
// User has access to name and created date by default.
|
||||
$this->assertText(t('Name'));
|
||||
$this->assertText(t('Created'));
|
||||
|
||||
// User does not by default have access to init, mail and status.
|
||||
$this->assertNoText(t('Init'));
|
||||
$this->assertNoText(t('Email'));
|
||||
$this->assertNoText(t('Status'));
|
||||
|
||||
// Assign sub-admin role to grant extra access.
|
||||
$user = $this->drupalCreateUser(['sub-admin']);
|
||||
$this->drupalLogin($user);
|
||||
$this->drupalGet($path);
|
||||
|
||||
// Access for init, mail and status is added in hook_entity_field_access().
|
||||
$this->assertText(t('Init'));
|
||||
$this->assertText(t('Email'));
|
||||
$this->assertText(t('Status'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\FunctionalJavascript;
|
||||
|
||||
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests user registration forms with additional fields.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class RegistrationWithUserFieldsTest extends WebDriverTestBase {
|
||||
|
||||
/**
|
||||
* WebAssert object.
|
||||
*
|
||||
* @var \Drupal\Tests\WebAssert
|
||||
*/
|
||||
protected $webAssert;
|
||||
|
||||
/**
|
||||
* DocumentElement object.
|
||||
*
|
||||
* @var \Behat\Mink\Element\DocumentElement
|
||||
*/
|
||||
protected $page;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['field_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->page = $this->getSession()->getPage();
|
||||
$this->webAssert = $this->assertSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Field API fields on user registration forms.
|
||||
*/
|
||||
public function testRegistrationWithUserFields() {
|
||||
// Create a field on 'user' entity type.
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => 'test_user_field',
|
||||
'entity_type' => 'user',
|
||||
'type' => 'test_field',
|
||||
'cardinality' => 1,
|
||||
]);
|
||||
$field_storage->save();
|
||||
$field = FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'label' => 'Some user field',
|
||||
'bundle' => 'user',
|
||||
'required' => TRUE,
|
||||
]);
|
||||
$field->save();
|
||||
|
||||
entity_get_form_display('user', 'user', 'default')
|
||||
->setComponent('test_user_field', ['type' => 'test_field_widget'])
|
||||
->save();
|
||||
$user_registration_form = entity_get_form_display('user', 'user', 'register');
|
||||
$user_registration_form->save();
|
||||
|
||||
// Check that the field does not appear on the registration form.
|
||||
$this->drupalGet('user/register');
|
||||
$this->webAssert->pageTextNotContains($field->label());
|
||||
|
||||
// Have the field appear on the registration form.
|
||||
$user_registration_form->setComponent('test_user_field', ['type' => 'test_field_widget'])->save();
|
||||
|
||||
$this->drupalGet('user/register');
|
||||
$this->webAssert->pageTextContains($field->label());
|
||||
|
||||
// In order to check the server side validation the native browser
|
||||
// validation for required fields needs to be circumvented.
|
||||
$session = $this->getSession();
|
||||
$session->executeScript("jQuery('#edit-test-user-field-0-value').prop('required', false);");
|
||||
|
||||
// Check that validation errors are correctly reported.
|
||||
$name = $this->randomMachineName();
|
||||
$this->page->fillField('edit-name', $name);
|
||||
$this->page->fillField('edit-mail', $name . '@example.com');
|
||||
|
||||
$this->page->pressButton('edit-submit');
|
||||
$this->webAssert->pageTextContains(t('@name field is required.', ['@name' => $field->label()]));
|
||||
|
||||
// Invalid input.
|
||||
$this->page->fillField('edit-test-user-field-0-value', '-1');
|
||||
$this->page->pressButton('edit-submit');
|
||||
$this->webAssert->pageTextContains($field->label() . ' does not accept the value -1.');
|
||||
|
||||
// Submit with valid data.
|
||||
$value = (string) mt_rand(1, 255);
|
||||
$this->page->fillField('edit-test-user-field-0-value', $value);
|
||||
$this->page->pressButton('edit-submit');
|
||||
// Check user fields.
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $name . '@example.com']);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertEquals($value, $new_user->test_user_field->value, 'The field value was correctly saved.');
|
||||
|
||||
// Check that the 'add more' button works.
|
||||
$field_storage->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
$field_storage->save();
|
||||
$name = $this->randomMachineName();
|
||||
$this->drupalGet('user/register');
|
||||
$this->page->fillField('edit-name', $name);
|
||||
$this->page->fillField('edit-mail', $name . '@example.com');
|
||||
$this->page->fillField('test_user_field[0][value]', $value);
|
||||
// Add two inputs.
|
||||
$this->page->pressButton('test_user_field_add_more');
|
||||
$this->webAssert->waitForElement('css', 'input[name="test_user_field[1][value]"]');
|
||||
$this->page->fillField('test_user_field[1][value]', $value . '1');
|
||||
$this->page->pressButton('test_user_field_add_more');
|
||||
$this->webAssert->waitForElement('css', 'input[name="test_user_field[2][value]"]');
|
||||
$this->page->fillField('test_user_field[2][value]', $value . '2');
|
||||
|
||||
// Submit with three values.
|
||||
$this->page->pressButton('edit-submit');
|
||||
|
||||
// Check user fields.
|
||||
$accounts = $this->container->get('entity_type.manager')
|
||||
->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $name . '@example.com']);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertEquals($value, $new_user->test_user_field[0]->value, t('The field value was correctly saved.'));
|
||||
$this->assertEquals($value . '1', $new_user->test_user_field[1]->value, t('The field value was correctly saved.'));
|
||||
$this->assertEquals($value . '2', $new_user->test_user_field[2]->value, t('The field value was correctly saved.'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Drupal\Tests\user\Kernel\Condition;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\user\Entity\User;
|
||||
@@ -151,7 +151,7 @@ class UserRoleConditionTest extends KernelTestBase {
|
||||
$condition->setConfig('roles', [$this->role->id() => $this->role->id()]);
|
||||
$condition->setConfig('negate', FALSE);
|
||||
$this->assertTrue($condition->execute(), 'Authenticated user is a member of the custom role.');
|
||||
$this->assertEqual($condition->summary(), SafeMarkup::format('The user is a member of @roles', ['@roles' => $this->role->label()]));
|
||||
$this->assertEqual($condition->summary(), new FormattableMarkup('The user is a member of @roles', ['@roles' => $this->role->label()]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -47,6 +47,10 @@ class MigrateUserProfileEntityDisplayTest extends MigrateDrupal6TestBase {
|
||||
|
||||
// Test PROFILE_HIDDEN field is hidden.
|
||||
$this->assertNull($display->getComponent('profile_sold_to'));
|
||||
|
||||
// Test a checkbox field.
|
||||
$component = $display->getComponent('profile_really_really_love_mig');
|
||||
$this->assertIdentical('list_default', $component['type']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ class MigrateUserProfileEntityFormDisplayTest extends MigrateDrupal6TestBase {
|
||||
$this->assertNull($display->getComponent('profile_sold_to'));
|
||||
|
||||
// Test that a checkbox field has the proper display label setting.
|
||||
$component = $display->getComponent('profile_love_migrations');
|
||||
$component = $display->getComponent('profile_really_really_love_mig');
|
||||
$this->assertIdentical('boolean_checkbox', $component['type']);
|
||||
$this->assertIdentical(TRUE, $component['settings']['display_label']);
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ class MigrateUserProfileFieldInstanceTest extends MigrateDrupal6TestBase {
|
||||
$this->assertIdentical("Enter your birth date and we'll send you a coupon.", $field->getDescription());
|
||||
|
||||
// Another migrated checkbox field, with a different source visibility setting.
|
||||
$field = FieldConfig::load('user.user.profile_love_migrations');
|
||||
$this->assertIdentical('I love migrations', $field->label());
|
||||
$field = FieldConfig::load('user.user.profile_really_really_love_mig');
|
||||
$this->assertIdentical('I really, really, really love migrations', $field->label());
|
||||
$this->assertIdentical("If you check this box, you love migrations.", $field->getDescription());
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,13 @@ EOT;
|
||||
$this->assertNull($user->profile_blog->title);
|
||||
$this->assertIdentical([], $user->profile_blog->options);
|
||||
$this->assertIdentical('http://example.com/blog', $user->profile_blog->uri);
|
||||
$this->assertNull($user->profile_love_migrations->value);
|
||||
|
||||
// Check that the source profile field names that are longer than 32
|
||||
// characters have been migrated.
|
||||
$this->assertNotNull($user->getFieldDefinition('profile_really_really_love_mig'));
|
||||
$this->assertNotNull($user->getFieldDefinition('profile_really_really_love_mig1'));
|
||||
$this->assertSame('1', $user->profile_really_really_love_mig->value);
|
||||
$this->assertNull($user->profile_really_really_love_mig1->value);
|
||||
|
||||
$user = User::load(8);
|
||||
$this->assertIdentical('Forward/slash', $user->profile_sold_to->value);
|
||||
|
||||
@@ -60,7 +60,7 @@ class MigrateUserRoleTest extends MigrateDrupal6TestBase {
|
||||
'access content',
|
||||
'migrate test anonymous permission',
|
||||
// From filter_format tables.
|
||||
'use text format filtered_html'
|
||||
'use text format filtered_html',
|
||||
];
|
||||
$this->assertRole('anonymous', $permissions, 1, $id_map);
|
||||
|
||||
@@ -81,7 +81,7 @@ class MigrateUserRoleTest extends MigrateDrupal6TestBase {
|
||||
'migrate test role 1 test permission',
|
||||
// From filter format.
|
||||
'use text format full_html',
|
||||
'use text format php_code'
|
||||
'use text format php_code',
|
||||
];
|
||||
$this->assertRole('migrate_test_role_1', $permissions, 3, $id_map);
|
||||
|
||||
@@ -126,7 +126,7 @@ class MigrateUserRoleTest extends MigrateDrupal6TestBase {
|
||||
'administrator1',
|
||||
'migrate_test_role_11',
|
||||
'migrate_test_role_21',
|
||||
'migrate_test_role_3_that_is_longer_than_thirty_two_characters1'
|
||||
'migrate_test_role_3_that_is_longer_than_thirty_two_characters1',
|
||||
];
|
||||
$this->assertEmpty(Role::loadMultiple($roles));
|
||||
|
||||
|
||||
@@ -24,11 +24,14 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
||||
*/
|
||||
public static $modules = [
|
||||
'comment',
|
||||
'content_translation',
|
||||
'datetime',
|
||||
'file',
|
||||
'image',
|
||||
'language',
|
||||
'link',
|
||||
// Required for translation migrations.
|
||||
'migrate_drupal_multilingual',
|
||||
'node',
|
||||
'system',
|
||||
'taxonomy',
|
||||
@@ -44,6 +47,9 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
||||
|
||||
// Prepare to migrate user pictures as well.
|
||||
$this->installEntitySchema('file');
|
||||
$this->installEntitySchema('comment');
|
||||
$this->installEntitySchema('node');
|
||||
$this->installEntitySchema('taxonomy_term');
|
||||
$this->createNodeCommentCombination('page');
|
||||
$this->createNodeCommentCombination('article');
|
||||
$this->createNodeCommentCombination('blog');
|
||||
@@ -59,6 +65,8 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
||||
'd7_field',
|
||||
'd7_field_instance',
|
||||
'd7_user',
|
||||
'd7_entity_translation_settings',
|
||||
'd7_user_entity_translation',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -81,8 +89,10 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
||||
* The last login time.
|
||||
* @param bool $blocked
|
||||
* Whether or not the account is blocked.
|
||||
* @param string $langcode
|
||||
* The user account's language code.
|
||||
* @param string $entity_langcode
|
||||
* The user entity language code.
|
||||
* @param string $prefered_langcode
|
||||
* The user prefered language code.
|
||||
* @param string $timezone
|
||||
* The user account's timezone name.
|
||||
* @param string $init
|
||||
@@ -96,7 +106,7 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
||||
* @param bool $has_picture
|
||||
* (optional) Whether the user is expected to have a picture attached.
|
||||
*/
|
||||
protected function assertEntity($id, $label, $mail, $password, $created, $access, $login, $blocked, $langcode, $timezone, $init, $roles, $field_integer, $field_file_target_id = FALSE, $has_picture = FALSE) {
|
||||
protected function assertEntity($id, $label, $mail, $password, $created, $access, $login, $blocked, $entity_langcode, $prefered_langcode, $timezone, $init, $roles, $field_integer, $field_file_target_id = FALSE, $has_picture = FALSE) {
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = User::load($id);
|
||||
$this->assertTrue($user instanceof UserInterface);
|
||||
@@ -115,20 +125,20 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
||||
// test if the value was imported correctly.
|
||||
$language_manager = $this->container->get('language_manager');
|
||||
$default_langcode = $language_manager->getDefaultLanguage()->getId();
|
||||
if ($langcode == '') {
|
||||
if ($prefered_langcode == '') {
|
||||
$this->assertSame('en', $user->langcode->value);
|
||||
$this->assertSame($default_langcode, $user->preferred_langcode->value);
|
||||
$this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
|
||||
}
|
||||
elseif ($language_manager->getLanguage($langcode) === NULL) {
|
||||
elseif ($language_manager->getLanguage($prefered_langcode) === NULL) {
|
||||
$this->assertSame($default_langcode, $user->langcode->value);
|
||||
$this->assertSame($default_langcode, $user->preferred_langcode->value);
|
||||
$this->assertSame($default_langcode, $user->preferred_admin_langcode->value);
|
||||
}
|
||||
else {
|
||||
$this->assertSame($langcode, $user->langcode->value);
|
||||
$this->assertSame($langcode, $user->preferred_langcode->value);
|
||||
$this->assertSame($langcode, $user->preferred_admin_langcode->value);
|
||||
$this->assertSame($entity_langcode, $user->langcode->value);
|
||||
$this->assertSame($prefered_langcode, $user->preferred_langcode->value);
|
||||
$this->assertSame($prefered_langcode, $user->preferred_admin_langcode->value);
|
||||
}
|
||||
|
||||
$this->assertSame($timezone, $user->getTimeZone());
|
||||
@@ -170,10 +180,21 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
||||
$roles[] = reset($role);
|
||||
}
|
||||
|
||||
$entity_translation = Database::getConnection('default', 'migrate')
|
||||
->select('entity_translation', 'et')
|
||||
->fields('et', ['language'])
|
||||
->condition('et.entity_type', 'user')
|
||||
->condition('et.entity_id', $source->uid)
|
||||
->condition('et.source', '')
|
||||
->execute()
|
||||
->fetchField();
|
||||
$entity_language = $entity_translation ?: $source->language;
|
||||
|
||||
$field_integer = Database::getConnection('default', 'migrate')
|
||||
->select('field_data_field_integer', 'fi')
|
||||
->fields('fi', ['field_integer_value'])
|
||||
->condition('fi.entity_id', $source->uid)
|
||||
->condition('fi.language', $entity_language)
|
||||
->execute()
|
||||
->fetchCol();
|
||||
$field_integer = !empty($field_integer) ? $field_integer : NULL;
|
||||
@@ -194,6 +215,7 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
||||
$source->access,
|
||||
$source->login,
|
||||
$source->status,
|
||||
$entity_language,
|
||||
$source->language,
|
||||
$source->timezone,
|
||||
$source->init,
|
||||
@@ -218,4 +240,45 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the Drupal 7 user entity translations to Drupal 8 migration.
|
||||
*/
|
||||
public function testUserEntityTranslations() {
|
||||
$manager = $this->container->get('content_translation.manager');
|
||||
|
||||
// Get the user and its translations.
|
||||
$user = User::load(2);
|
||||
$user_fr = $user->getTranslation('fr');
|
||||
$user_is = $user->getTranslation('is');
|
||||
|
||||
// Test that fields translated with Entity Translation are migrated.
|
||||
$this->assertSame('99', $user->field_integer->value);
|
||||
$this->assertSame('9', $user_fr->field_integer->value);
|
||||
$this->assertSame('1', $user_is->field_integer->value);
|
||||
|
||||
// Test that the French translation metadata is correctly migrated.
|
||||
$metadata_fr = $manager->getTranslationMetadata($user_fr);
|
||||
$this->assertSame('en', $metadata_fr->getSource());
|
||||
$this->assertSame('1', $metadata_fr->getAuthor()->uid->value);
|
||||
$this->assertSame('1531663916', $metadata_fr->getCreatedTime());
|
||||
$this->assertFalse($metadata_fr->isOutdated());
|
||||
$this->assertFalse($metadata_fr->isPublished());
|
||||
|
||||
// Test that the Icelandic translation metadata is correctly migrated.
|
||||
$metadata_is = $manager->getTranslationMetadata($user_is);
|
||||
$this->assertSame('en', $metadata_is->getSource());
|
||||
$this->assertSame('2', $metadata_is->getAuthor()->uid->value);
|
||||
$this->assertSame('1531663925', $metadata_is->getCreatedTime());
|
||||
$this->assertTrue($metadata_is->isOutdated());
|
||||
$this->assertTrue($metadata_is->isPublished());
|
||||
|
||||
// Test that untranslatable properties are the same as the source language.
|
||||
$this->assertSame($user->label(), $user_fr->label());
|
||||
$this->assertSame($user->label(), $user_is->label());
|
||||
$this->assertSame($user->getEmail(), $user_fr->getEmail());
|
||||
$this->assertSame($user->getEmail(), $user_is->getEmail());
|
||||
$this->assertSame($user->getPassword(), $user_fr->getPassword());
|
||||
$this->assertSame($user->getPassword(), $user_is->getPassword());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ class ProfileFieldTest extends MigrateSqlSourceTestBase {
|
||||
'fid' => 4,
|
||||
'uid' => 1,
|
||||
'value' => 'yellow',
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
// Expected options are:
|
||||
@@ -114,7 +114,7 @@ class ProfileFieldTest extends MigrateSqlSourceTestBase {
|
||||
'blue' => 'blue',
|
||||
'green' => 'green',
|
||||
'yellow' => 'yellow',
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
$tests[0]['expected_data'] = $profile_fields;
|
||||
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests D7 user entity translation source plugin.
|
||||
*
|
||||
* @covers \Drupal\user\Plugin\migrate\source\d7\UserEntityTranslation
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserEntityTranslationTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['user', 'migrate_drupal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerSource() {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['entity_translation'] = [
|
||||
[
|
||||
'entity_type' => 'user',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'en',
|
||||
'source' => '',
|
||||
'uid' => 1,
|
||||
'status' => 1,
|
||||
'translate' => 0,
|
||||
'created' => 1531343498,
|
||||
'changed' => 1531343498,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'user',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'fr',
|
||||
'source' => 'en',
|
||||
'uid' => 2,
|
||||
'status' => 1,
|
||||
'translate' => 1,
|
||||
'created' => 1531343508,
|
||||
'changed' => 1531343508,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'user',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'es',
|
||||
'source' => 'en',
|
||||
'uid' => 1,
|
||||
'status' => 0,
|
||||
'translate' => 0,
|
||||
'created' => 1531343456,
|
||||
'changed' => 1531343456,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_config'] = [
|
||||
[
|
||||
'id' => 1,
|
||||
'field_name' => 'field_test',
|
||||
'type' => 'text',
|
||||
'module' => 'text',
|
||||
'active' => 1,
|
||||
'storage_type' => 'field_sql_storage',
|
||||
'storage_module' => 'field_sql_storage',
|
||||
'storage_active' => 1,
|
||||
'locked' => 1,
|
||||
'data' => 'a:0:{}',
|
||||
'cardinality' => 1,
|
||||
'translatable' => 1,
|
||||
'deleted' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_config_instance'] = [
|
||||
[
|
||||
'id' => 1,
|
||||
'field_id' => 1,
|
||||
'field_name' => 'field_test',
|
||||
'entity_type' => 'user',
|
||||
'bundle' => 'user',
|
||||
'data' => 'a:0:{}',
|
||||
'deleted' => 0,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_data_field_test'] = [
|
||||
[
|
||||
'entity_type' => 'user',
|
||||
'bundle' => 'user',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'en',
|
||||
'delta' => 0,
|
||||
'field_test_value' => 'English field',
|
||||
'field_test_format' => NULL,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'user',
|
||||
'bundle' => 'user',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'fr',
|
||||
'delta' => 0,
|
||||
'field_test_value' => 'French field',
|
||||
'field_test_format' => NULL,
|
||||
],
|
||||
[
|
||||
'entity_type' => 'user',
|
||||
'bundle' => 'user',
|
||||
'deleted' => 0,
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'es',
|
||||
'delta' => 0,
|
||||
'field_test_value' => 'Spanish field',
|
||||
'field_test_format' => NULL,
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['users'] = [
|
||||
[
|
||||
'uid' => 1,
|
||||
'name' => 'admin',
|
||||
'pass' => 'password123',
|
||||
'mail' => 'admin@example.com',
|
||||
'theme' => '',
|
||||
'signature' => '',
|
||||
'signature_format' => 'filtered_html',
|
||||
'created' => 1531343456,
|
||||
'access' => 1531343456,
|
||||
'login' => 1531343456,
|
||||
'status' => 1,
|
||||
'timezone' => 'America/New_York',
|
||||
'language' => 'fr',
|
||||
'picture' => 0,
|
||||
'init' => 'admin@example.com',
|
||||
'data' => 'a:0:{}',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['users_roles'] = [
|
||||
[
|
||||
'uid' => 1,
|
||||
'rid' => 3,
|
||||
],
|
||||
];
|
||||
|
||||
// The expected results.
|
||||
$tests[0]['expected_data'] = [
|
||||
[
|
||||
'entity_type' => 'user',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'fr',
|
||||
'source' => 'en',
|
||||
'uid' => 2,
|
||||
'status' => 1,
|
||||
'translate' => 1,
|
||||
'created' => 1531343508,
|
||||
'changed' => 1531343508,
|
||||
'field_test' => [
|
||||
[
|
||||
'value' => 'French field',
|
||||
'format' => NULL,
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'entity_type' => 'user',
|
||||
'entity_id' => 1,
|
||||
'revision_id' => 1,
|
||||
'language' => 'es',
|
||||
'source' => 'en',
|
||||
'uid' => 1,
|
||||
'status' => 0,
|
||||
'translate' => 0,
|
||||
'created' => 1531343456,
|
||||
'changed' => 1531343456,
|
||||
'field_test' => [
|
||||
[
|
||||
'value' => 'Spanish field',
|
||||
'format' => NULL,
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,12 @@ class UserTest extends MigrateSqlSourceTestBase {
|
||||
$tests = [];
|
||||
|
||||
// The source data.
|
||||
$tests[0]['source_data']['field_config'] = [
|
||||
[
|
||||
'id' => '11',
|
||||
'translatable' => '0',
|
||||
],
|
||||
];
|
||||
$tests[0]['source_data']['field_config_instance'] = [
|
||||
[
|
||||
'id' => '33',
|
||||
|
||||
@@ -24,8 +24,8 @@ class UserAccountFormFieldsTest extends KernelTestBase {
|
||||
* Tests the root user account form section in the "Configure site" form.
|
||||
*/
|
||||
public function testInstallConfigureForm() {
|
||||
require_once \Drupal::root() . '/core/includes/install.core.inc';
|
||||
require_once \Drupal::root() . '/core/includes/install.inc';
|
||||
require_once $this->root . '/core/includes/install.core.inc';
|
||||
require_once $this->root . '/core/includes/install.inc';
|
||||
$install_state = install_state_defaults();
|
||||
$form_state = new FormState();
|
||||
$form_state->addBuildInfo('args', [&$install_state]);
|
||||
|
||||
@@ -28,7 +28,6 @@ class UserInstallTest extends KernelTestBase {
|
||||
user_install();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that the initial users have correct values.
|
||||
*/
|
||||
|
||||
@@ -215,7 +215,7 @@ class UserValidationTest extends KernelTestBase {
|
||||
protected function assertAllowedValuesViolation(EntityInterface $entity, $field_name) {
|
||||
$violations = $entity->validate();
|
||||
$this->assertEqual(count($violations), 1, "Allowed values violation for $field_name found.");
|
||||
$this->assertEqual($violations[0]->getPropertyPath(), "$field_name.0.value");
|
||||
$this->assertEqual($violations[0]->getPropertyPath(), $field_name === 'langcode' ? "$field_name.0" : "$field_name.0.value");
|
||||
$this->assertEqual($violations[0]->getMessage(), t('The value you selected is not a valid choice.'));
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user