updated core from 8.4 to 8.5 : bug with login_destination

This commit is contained in:
Bachir Soussi Chiadmi
2018-03-13 14:01:21 +01:00
parent 0d78da249b
commit e668535a4e
3486 changed files with 89604 additions and 33283 deletions
@@ -11,6 +11,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Configure user settings for this site.
*
* @internal
*/
class AccountSettingsForm extends ConfigFormBase {
@@ -50,6 +50,12 @@ class CurrentUserContext implements ContextProviderInterface {
public function getRuntimeContexts(array $unqualified_context_ids) {
$current_user = $this->userStorage->load($this->account->id());
if ($current_user) {
// @todo Do not validate protected fields to avoid bug in TypedData,
// remove this in https://www.drupal.org/project/drupal/issues/2934192.
$current_user->_skipProtectedUserFieldConstraint = TRUE;
}
$context = new Context(new ContextDefinition('entity:user', $this->t('Current user')), $current_user);
$cacheability = new CacheableMetadata();
$cacheability->setCacheContexts(['user']);
+4
View File
@@ -9,6 +9,8 @@ use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Language\LanguageInterface;
use Drupal\user\RoleInterface;
use Drupal\user\StatusItem;
use Drupal\user\TimeZoneItem;
use Drupal\user\UserInterface;
/**
@@ -498,11 +500,13 @@ class User extends ContentEntityBase implements UserInterface {
->addPropertyConstraints('value', [
'AllowedValues' => ['callback' => __CLASS__ . '::getAllowedTimezones'],
]);
$fields['timezone']->getItemDefinition()->setClass(TimeZoneItem::class);
$fields['status'] = BaseFieldDefinition::create('boolean')
->setLabel(t('User status'))
->setDescription(t('Whether the user is active or blocked.'))
->setDefaultValue(FALSE);
$fields['status']->getItemDefinition()->setClass(StatusItem::class);
$fields['created'] = BaseFieldDefinition::create('created')
->setLabel(t('Created'))
@@ -7,6 +7,8 @@ use Drupal\Core\Form\FormStateInterface;
/**
* Provides a confirmation form for cancelling user account.
*
* @internal
*/
class UserCancelForm extends ContentEntityConfirmFormBase {
@@ -12,6 +12,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a user login form.
*
* @internal
*/
class UserLoginForm extends FormBase {
@@ -6,19 +6,21 @@ use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\user\PrivateTempStoreFactory;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Drupal\user\UserStorageInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a confirmation form for cancelling multiple user accounts.
*
* @internal
*/
class UserMultipleCancelConfirm extends ConfirmFormBase {
/**
* The temp store factory.
*
* @var \Drupal\user\PrivateTempStoreFactory
* @var \Drupal\Core\TempStore\PrivateTempStoreFactory
*/
protected $tempStoreFactory;
@@ -39,7 +41,7 @@ class UserMultipleCancelConfirm extends ConfirmFormBase {
/**
* Constructs a new UserMultipleCancelConfirm.
*
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
* The temp store factory.
* @param \Drupal\user\UserStorageInterface $user_storage
* The user storage.
@@ -57,7 +59,7 @@ class UserMultipleCancelConfirm extends ConfirmFormBase {
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('user.private_tempstore'),
$container->get('tempstore.private'),
$container->get('entity.manager')->getStorage('user'),
$container->get('entity.manager')
);
@@ -11,6 +11,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides a user password reset form.
*
* @internal
*/
class UserPasswordForm extends FormBase {
@@ -9,6 +9,8 @@ use Drupal\Core\Url;
/**
* Form controller for the user password forms.
*
* @internal
*/
class UserPasswordResetForm extends FormBase {
@@ -11,6 +11,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Provides the user permissions administration form.
*
* @internal
*/
class UserPermissionsForm extends FormBase {
@@ -127,6 +129,21 @@ class UserPermissionsForm extends FormBase {
$permissions_by_provider[$permission['provider']][$permission_name] = $permission;
}
// Move the access content permission to the Node module if it is installed.
if ($this->moduleHandler->moduleExists('node')) {
// Insert 'access content' before the 'view own unpublished content' key
// in order to maintain the UI even though the permission is provided by
// the system module.
$keys = array_keys($permissions_by_provider['node']);
$offset = (int) array_search('view own unpublished content', $keys);
$permissions_by_provider['node'] = array_merge(
array_slice($permissions_by_provider['node'], 0, $offset),
['access content' => $permissions_by_provider['system']['access content']],
array_slice($permissions_by_provider['node'], $offset)
);
unset($permissions_by_provider['system']['access content']);
}
foreach ($permissions_by_provider as $provider => $permissions) {
// Module name.
$form['permissions'][$provider] = [
@@ -7,6 +7,8 @@ use Drupal\user\RoleInterface;
/**
* Provides the user permissions administration form for a specific role.
*
* @internal
*/
class UserPermissionsRoleSpecificForm extends UserPermissionsForm {
@@ -5,7 +5,7 @@ namespace Drupal\user\Plugin\Action;
use Drupal\Core\Action\ActionBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\user\PrivateTempStoreFactory;
use Drupal\Core\TempStore\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
@@ -23,7 +23,7 @@ class CancelUser extends ActionBase implements ContainerFactoryPluginInterface {
/**
* The tempstore factory.
*
* @var \Drupal\user\PrivateTempStoreFactory
* @var \Drupal\Core\TempStore\PrivateTempStoreFactory
*/
protected $tempStoreFactory;
@@ -43,7 +43,7 @@ class CancelUser extends ActionBase implements ContainerFactoryPluginInterface {
* The plugin ID for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
* The tempstore factory.
* @param \Drupal\Core\Session\AccountInterface $current_user
* Current user.
@@ -63,7 +63,7 @@ class CancelUser extends ActionBase implements ContainerFactoryPluginInterface {
$configuration,
$plugin_id,
$plugin_definition,
$container->get('user.private_tempstore'),
$container->get('tempstore.private'),
$container->get('current_user')
);
}
@@ -28,6 +28,7 @@ class ProfileValues extends Migration {
'ignore_map' => TRUE,
] + $this->source;
$definition['destination']['plugin'] = 'null';
$definition['idMap']['plugin'] = 'null';
try {
$profile_field_migration = $this->migrationPluginManager->createStubMigration($definition);
$source_plugin = $profile_field_migration->getSourcePlugin();
@@ -21,6 +21,7 @@ class User extends FieldMigration {
'ignore_map' => TRUE,
] + $this->source;
$definition['destination']['plugin'] = 'null';
$definition['idMap']['plugin'] = 'null';
if (\Drupal::moduleHandler()->moduleExists('field')) {
$definition['source']['plugin'] = 'd7_field_instance';
$field_migration = $this->migrationPluginManager->createStubMigration($definition);
@@ -127,4 +127,18 @@ class EntityUser extends EntityContentBase {
}
}
/**
* {@inheritdoc}
*/
public function getHighestId() {
$highest_id = parent::getHighestId();
// Every Drupal site must have a user with UID of 1 and it's normal for
// migrations to overwrite this user.
if ($highest_id === 1) {
return 0;
}
return $highest_id;
}
}
@@ -3,8 +3,8 @@
namespace Drupal\user\Plugin\views\field;
use Drupal\Core\Form\FormStateInterface;
use Drupal\system\Plugin\views\field\BulkForm;
use Drupal\user\UserInterface;
use Drupal\views\Plugin\views\field\BulkForm;
/**
* Defines a user operations bulk form element.
@@ -74,10 +74,20 @@ class Roles extends ManyToOne {
*/
public function calculateDependencies() {
$dependencies = [];
if (in_array($this->operator, ['empty', 'not empty'])) {
return $dependencies;
}
foreach ($this->value as $role_id) {
// The value might be a string due to the wrong plugin being used for role
// field data, and subsequently the incorrect config schema object and
// value. In the empty case stop early. Otherwise we cast it to an array
// later.
if (is_string($this->value) && $this->value === '') {
return [];
}
foreach ((array) $this->value as $role_id) {
$role = $this->roleStorage->load($role_id);
$dependencies[$role->getConfigDependencyKey()][] = $role->getConfigDependencyName();
}
+15 -202
View File
@@ -2,212 +2,25 @@
namespace Drupal\user;
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Core\TempStore\PrivateTempStore as CorePrivateTempStore;
@trigger_error('\Drupal\user\PrivateTempStore is scheduled for removal in Drupal 9.0.0. Use \Drupal\Core\TempStore\PrivateTempStore instead. See https://www.drupal.org/node/2935639.', E_USER_DEPRECATED);
/**
* In order to preserve BC alias the core exception.
*/
if (!class_exists('\Drupal\user\TempStoreException')) {
class_alias('\Drupal\Core\TempStore\TempStoreException', '\Drupal\user\TempStoreException');
}
/**
* Stores and retrieves temporary data for a given owner.
*
* A PrivateTempStore can be used to make temporary, non-cache data available
* across requests. The data for the PrivateTempStore is stored in one
* key/value collection. PrivateTempStore data expires automatically after a
* given timeframe.
* @deprecated in Drupal 8.5.x, to be removed before Drupal 9.0.0.
* Use \Drupal\Core\TempStore\PrivateTempStore instead.
*
* The PrivateTempStore is different from a cache, because the data in it is not
* yet saved permanently and so it cannot be rebuilt. Typically, the
* PrivateTempStore might be used to store work in progress that is later saved
* permanently elsewhere, e.g. autosave data, multistep forms, or in-progress
* changes to complex configuration that are not ready to be saved.
*
* The PrivateTempStore differs from the SharedTempStore in that all keys are
* ensured to be unique for a particular user and users can never share data. If
* you want to be able to share data between users or use it for locking, use
* \Drupal\user\SharedTempStore.
* @see \Drupal\Core\TempStore\PrivateTempStore
* @see https://www.drupal.org/node/2935639
*/
class PrivateTempStore {
/**
* The key/value storage object used for this data.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
*/
protected $storage;
/**
* The lock object used for this data.
*
* @var \Drupal\Core\Lock\LockBackendInterface
*/
protected $lockBackend;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The time to live for items in seconds.
*
* By default, data is stored for one week (604800 seconds) before expiring.
*
* @var int
*/
protected $expire;
/**
* Constructs a new object for accessing data from a key/value store.
*
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $storage
* The key/value storage object used for this data. Each storage object
* represents a particular collection of data and will contain any number
* of key/value pairs.
* @param \Drupal\Core\Lock\LockBackendInterface $lock_backend
* The lock object used for this data.
* @param \Drupal\Core\Session\AccountProxyInterface $current_user
* The current user account.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param int $expire
* The time to live for items, in seconds.
*/
public function __construct(KeyValueStoreExpirableInterface $storage, LockBackendInterface $lock_backend, AccountProxyInterface $current_user, RequestStack $request_stack, $expire = 604800) {
$this->storage = $storage;
$this->lockBackend = $lock_backend;
$this->currentUser = $current_user;
$this->requestStack = $request_stack;
$this->expire = $expire;
}
/**
* Retrieves a value from this PrivateTempStore for a given key.
*
* @param string $key
* The key of the data to retrieve.
*
* @return mixed
* The data associated with the key, or NULL if the key does not exist.
*/
public function get($key) {
$key = $this->createkey($key);
if (($object = $this->storage->get($key)) && ($object->owner == $this->getOwner())) {
return $object->data;
}
}
/**
* Stores a particular key/value pair in this PrivateTempStore.
*
* @param string $key
* The key of the data to store.
* @param mixed $value
* The data to store.
*
* @throws \Drupal\user\TempStoreException
* Thrown when a lock for the backend storage could not be acquired.
*/
public function set($key, $value) {
$key = $this->createkey($key);
if (!$this->lockBackend->acquire($key)) {
$this->lockBackend->wait($key);
if (!$this->lockBackend->acquire($key)) {
throw new TempStoreException("Couldn't acquire lock to update item '$key' in '{$this->storage->getCollectionName()}' temporary storage.");
}
}
$value = (object) [
'owner' => $this->getOwner(),
'data' => $value,
'updated' => (int) $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME'),
];
$this->storage->setWithExpire($key, $value, $this->expire);
$this->lockBackend->release($key);
}
/**
* Returns the metadata associated with a particular key/value pair.
*
* @param string $key
* The key of the data to store.
*
* @return mixed
* An object with the owner and updated time if the key has a value, or
* NULL otherwise.
*/
public function getMetadata($key) {
$key = $this->createkey($key);
// Fetch the key/value pair and its metadata.
$object = $this->storage->get($key);
if ($object) {
// Don't keep the data itself in memory.
unset($object->data);
return $object;
}
}
/**
* Deletes data from the store for a given key and releases the lock on it.
*
* @param string $key
* The key of the data to delete.
*
* @return bool
* TRUE if the object was deleted or does not exist, FALSE if it exists but
* is not owned by $this->owner.
*
* @throws \Drupal\user\TempStoreException
* Thrown when a lock for the backend storage could not be acquired.
*/
public function delete($key) {
$key = $this->createkey($key);
if (!$object = $this->storage->get($key)) {
return TRUE;
}
elseif ($object->owner != $this->getOwner()) {
return FALSE;
}
if (!$this->lockBackend->acquire($key)) {
$this->lockBackend->wait($key);
if (!$this->lockBackend->acquire($key)) {
throw new TempStoreException("Couldn't acquire lock to delete item '$key' from '{$this->storage->getCollectionName()}' temporary storage.");
}
}
$this->storage->delete($key);
$this->lockBackend->release($key);
return TRUE;
}
/**
* Ensures that the key is unique for a user.
*
* @param string $key
* The key.
*
* @return string
* The unique key for the user.
*/
protected function createkey($key) {
return $this->getOwner() . ':' . $key;
}
/**
* Gets the current owner based on the current user or the session ID.
*
* @return string
* The owner.
*/
protected function getOwner() {
return $this->currentUser->id() ?: $this->requestStack->getCurrentRequest()->getSession()->getId();
}
class PrivateTempStore extends CorePrivateTempStore {
}
@@ -2,72 +2,20 @@
namespace Drupal\user;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Core\TempStore\PrivateTempStoreFactory as CorePrivateTempStoreFactory;
@trigger_error('\Drupal\user\PrivateTempStoreFactory is scheduled for removal in Drupal 9.0.0. Use \Drupal\Core\TempStore\PrivateTempStoreFactory instead. See https://www.drupal.org/node/2935639.', E_USER_DEPRECATED);
/**
* Creates a PrivateTempStore object for a given collection.
*
* @deprecated in Drupal 8.5.x, to be removed before Drupal 9.0.0.
* Use \Drupal\Core\TempStore\PrivateTempStoreFactory instead.
*
* @see \Drupal\Core\TempStore\PrivateTempStoreFactory
* @see https://www.drupal.org/node/2935639
*/
class PrivateTempStoreFactory {
/**
* The storage factory creating the backend to store the data.
*
* @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface
*/
protected $storageFactory;
/**
* The lock object used for this data.
*
* @var \Drupal\Core\Lock\LockBackendInterface
*/
protected $lockBackend;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The time to live for items in seconds.
*
* @var int
*/
protected $expire;
/**
* Constructs a Drupal\user\PrivateTempStoreFactory object.
*
* @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $storage_factory
* The key/value store factory.
* @param \Drupal\Core\Lock\LockBackendInterface $lock_backend
* The lock object used for this data.
* @param \Drupal\Core\Session\AccountProxyInterface $current_user
* The current account.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param int $expire
* The time to live for items, in seconds.
*/
public function __construct(KeyValueExpirableFactoryInterface $storage_factory, LockBackendInterface $lock_backend, AccountProxyInterface $current_user, RequestStack $request_stack, $expire = 604800) {
$this->storageFactory = $storage_factory;
$this->lockBackend = $lock_backend;
$this->currentUser = $current_user;
$this->requestStack = $request_stack;
$this->expire = $expire;
}
class PrivateTempStoreFactory extends CorePrivateTempStoreFactory {
/**
* Creates a PrivateTempStore.
+2
View File
@@ -6,6 +6,8 @@ use Drupal\Core\Form\FormStateInterface;
/**
* Form handler for the profile forms.
*
* @internal
*/
class ProfileForm extends AccountForm {
+2
View File
@@ -6,6 +6,8 @@ use Drupal\Core\Form\FormStateInterface;
/**
* Form handler for the user register forms.
*
* @internal
*/
class RegisterForm extends AccountForm {
+2
View File
@@ -7,6 +7,8 @@ use Drupal\Core\Form\FormStateInterface;
/**
* Form controller for the role entity edit forms.
*
* @internal
*/
class RoleForm extends EntityForm {
+15 -268
View File
@@ -2,278 +2,25 @@
namespace Drupal\user;
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
use Drupal\Core\Lock\LockBackendInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Core\TempStore\SharedTempStore as CoreSharedTempStore;
@trigger_error('\Drupal\user\SharedTempStore is scheduled for removal in Drupal 9.0.0. Use \Drupal\Core\TempStore\SharedTempStore instead. See https://www.drupal.org/node/2935639.', E_USER_DEPRECATED);
/**
* In order to preserve BC alias the core exception.
*/
if (!class_exists('\Drupal\user\TempStoreException')) {
class_alias('\Drupal\Core\TempStore\TempStoreException', '\Drupal\user\TempStoreException');
}
/**
* Stores and retrieves temporary data for a given owner.
*
* A SharedTempStore can be used to make temporary, non-cache data available
* across requests. The data for the SharedTempStore is stored in one key/value
* collection. SharedTempStore data expires automatically after a given
* timeframe.
* @deprecated in Drupal 8.5.x, to be removed before Drupal 9.0.0.
* Use \Drupal\Core\TempStore\SharedTempStore instead.
*
* The SharedTempStore is different from a cache, because the data in it is not
* yet saved permanently and so it cannot be rebuilt. Typically, the
* SharedTempStore might be used to store work in progress that is later saved
* permanently elsewhere, e.g. autosave data, multistep forms, or in-progress
* changes to complex configuration that are not ready to be saved.
*
* Each SharedTempStore belongs to a particular owner (e.g. a user, session, or
* process). Multiple owners may use the same key/value collection, and the
* owner is stored along with the key/value pair.
*
* Every key is unique within the collection, so the SharedTempStore can check
* whether a particular key is already set by a different owner. This is
* useful for informing one owner that the data is already in use by another;
* for example, to let one user know that another user is in the process of
* editing certain data, or even to restrict other users from editing it at
* the same time. It is the responsibility of the implementation to decide
* when and whether one owner can use or update another owner's data.
*
* If you want to be able to ensure that the data belongs to the current user,
* use \Drupal\user\PrivateTempStore.
* @see \Drupal\Core\TempStore\SharedTempStore
* @see https://www.drupal.org/node/2935639
*/
class SharedTempStore {
/**
* The key/value storage object used for this data.
*
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
*/
protected $storage;
/**
* The lock object used for this data.
*
* @var \Drupal\Core\Lock\LockBackendInterface
*/
protected $lockBackend;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The owner key to store along with the data (e.g. a user or session ID).
*
* @var mixed
*/
protected $owner;
/**
* The time to live for items in seconds.
*
* By default, data is stored for one week (604800 seconds) before expiring.
*
* @var int
*/
protected $expire;
/**
* Constructs a new object for accessing data from a key/value store.
*
* @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $storage
* The key/value storage object used for this data. Each storage object
* represents a particular collection of data and will contain any number
* of key/value pairs.
* @param \Drupal\Core\Lock\LockBackendInterface $lock_backend
* The lock object used for this data.
* @param mixed $owner
* The owner key to store along with the data (e.g. a user or session ID).
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param int $expire
* The time to live for items, in seconds.
*/
public function __construct(KeyValueStoreExpirableInterface $storage, LockBackendInterface $lock_backend, $owner, RequestStack $request_stack, $expire = 604800) {
$this->storage = $storage;
$this->lockBackend = $lock_backend;
$this->owner = $owner;
$this->requestStack = $request_stack;
$this->expire = $expire;
}
/**
* Retrieves a value from this SharedTempStore for a given key.
*
* @param string $key
* The key of the data to retrieve.
*
* @return mixed
* The data associated with the key, or NULL if the key does not exist.
*/
public function get($key) {
if ($object = $this->storage->get($key)) {
return $object->data;
}
}
/**
* Retrieves a value from this SharedTempStore for a given key.
*
* Only returns the value if the value is owned by $this->owner.
*
* @param string $key
* The key of the data to retrieve.
*
* @return mixed
* The data associated with the key, or NULL if the key does not exist.
*/
public function getIfOwner($key) {
if (($object = $this->storage->get($key)) && ($object->owner == $this->owner)) {
return $object->data;
}
}
/**
* Stores a particular key/value pair only if the key doesn't already exist.
*
* @param string $key
* The key of the data to check and store.
* @param mixed $value
* The data to store.
*
* @return bool
* TRUE if the data was set, or FALSE if it already existed.
*/
public function setIfNotExists($key, $value) {
$value = (object) [
'owner' => $this->owner,
'data' => $value,
'updated' => (int) $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME'),
];
return $this->storage->setWithExpireIfNotExists($key, $value, $this->expire);
}
/**
* Stores a particular key/value pair in this SharedTempStore.
*
* Only stores the given key/value pair if it does not exist yet or is owned
* by $this->owner.
*
* @param string $key
* The key of the data to store.
* @param mixed $value
* The data to store.
*
* @return bool
* TRUE if the data was set, or FALSE if it already exists and is not owned
* by $this->user.
*
* @throws \Drupal\user\TempStoreException
* Thrown when a lock for the backend storage could not be acquired.
*/
public function setIfOwner($key, $value) {
if ($this->setIfNotExists($key, $value)) {
return TRUE;
}
if (($object = $this->storage->get($key)) && ($object->owner == $this->owner)) {
$this->set($key, $value);
return TRUE;
}
return FALSE;
}
/**
* Stores a particular key/value pair in this SharedTempStore.
*
* @param string $key
* The key of the data to store.
* @param mixed $value
* The data to store.
*
* @throws \Drupal\user\TempStoreException
* Thrown when a lock for the backend storage could not be acquired.
*/
public function set($key, $value) {
if (!$this->lockBackend->acquire($key)) {
$this->lockBackend->wait($key);
if (!$this->lockBackend->acquire($key)) {
throw new TempStoreException("Couldn't acquire lock to update item '$key' in '{$this->storage->getCollectionName()}' temporary storage.");
}
}
$value = (object) [
'owner' => $this->owner,
'data' => $value,
'updated' => (int) $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME'),
];
$this->storage->setWithExpire($key, $value, $this->expire);
$this->lockBackend->release($key);
}
/**
* Returns the metadata associated with a particular key/value pair.
*
* @param string $key
* The key of the data to store.
*
* @return mixed
* An object with the owner and updated time if the key has a value, or
* NULL otherwise.
*/
public function getMetadata($key) {
// Fetch the key/value pair and its metadata.
$object = $this->storage->get($key);
if ($object) {
// Don't keep the data itself in memory.
unset($object->data);
return $object;
}
}
/**
* Deletes data from the store for a given key and releases the lock on it.
*
* @param string $key
* The key of the data to delete.
*
* @throws \Drupal\user\TempStoreException
* Thrown when a lock for the backend storage could not be acquired.
*/
public function delete($key) {
if (!$this->lockBackend->acquire($key)) {
$this->lockBackend->wait($key);
if (!$this->lockBackend->acquire($key)) {
throw new TempStoreException("Couldn't acquire lock to delete item '$key' from {$this->storage->getCollectionName()} temporary storage.");
}
}
$this->storage->delete($key);
$this->lockBackend->release($key);
}
/**
* Deletes data from the store for a given key and releases the lock on it.
*
* Only delete the given key if it is owned by $this->owner.
*
* @param string $key
* The key of the data to delete.
*
* @return bool
* TRUE if the object was deleted or does not exist, FALSE if it exists but
* is not owned by $this->owner.
*
* @throws \Drupal\user\TempStoreException
* Thrown when a lock for the backend storage could not be acquired.
*/
public function deleteIfOwner($key) {
if (!$object = $this->storage->get($key)) {
return TRUE;
}
elseif ($object->owner == $this->owner) {
$this->delete($key);
return TRUE;
}
return FALSE;
}
class SharedTempStore extends CoreSharedTempStore {
}
@@ -2,61 +2,20 @@
namespace Drupal\user;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
use Drupal\Core\Lock\LockBackendInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Drupal\Core\TempStore\SharedTempStoreFactory as CoreSharedTempStoreFactory;
@trigger_error('\Drupal\user\SharedTempStoreFactory is scheduled for removal in Drupal 9.0.0. Use \Drupal\Core\TempStore\SharedTempStoreFactory instead. See https://www.drupal.org/node/2935639.', E_USER_DEPRECATED);
/**
* Creates a shared temporary storage for a collection.
*
* @deprecated in Drupal 8.5.x, to be removed before Drupal 9.0.0.
* Use \Drupal\Core\TempStore\SharedTempStoreFactory instead.
*
* @see \Drupal\Core\TempStore\SharedTempStoreFactory
* @see https://www.drupal.org/node/2935639
*/
class SharedTempStoreFactory {
/**
* The storage factory creating the backend to store the data.
*
* @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface
*/
protected $storageFactory;
/**
* The lock object used for this data.
*
* @var \Drupal\Core\Lock\LockBackendInterface
*/
protected $lockBackend;
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The time to live for items in seconds.
*
* @var int
*/
protected $expire;
/**
* Constructs a Drupal\user\SharedTempStoreFactory object.
*
* @param \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface $storage_factory
* The key/value store factory.
* @param \Drupal\Core\Lock\LockBackendInterface $lock_backend
* The lock object used for this data.
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
* The request stack.
* @param int $expire
* The time to live for items, in seconds.
*/
public function __construct(KeyValueExpirableFactoryInterface $storage_factory, LockBackendInterface $lock_backend, RequestStack $request_stack, $expire = 604800) {
$this->storageFactory = $storage_factory;
$this->lockBackend = $lock_backend;
$this->requestStack = $request_stack;
$this->expire = $expire;
}
class SharedTempStoreFactory extends CoreSharedTempStoreFactory {
/**
* Creates a SharedTempStore for the current user or anonymous session.
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace Drupal\user;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\BooleanItem;
/**
* Defines the 'status' entity field type.
*
* @todo Consider making this a full field type plugin in
* https://www.drupal.org/project/drupal/issues/2936864.
*/
class StatusItem extends BooleanItem {
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
// Always generate a sample with an enabled status.
$values['value'] = 1;
return $values;
}
}
@@ -1,11 +0,0 @@
<?php
namespace Drupal\user;
/**
* Thrown by SharedTempStore and PrivateTempStore if they cannot acquire a lock.
*
* @see \Drupal\user\SharedTempStore
* @see \Drupal\user\PrivateTempStore
*/
class TempStoreException extends \Exception {}
@@ -2,6 +2,7 @@
namespace Drupal\user\Tests;
use Drupal\Core\Url;
use Drupal\rest\Tests\RESTTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
@@ -166,7 +167,7 @@ class RestRegisterUserTest extends RESTTestBase {
*/
protected function registerRequest($name, $include_password = TRUE) {
$serialized = $this->createSerializedUser($name, $include_password);
$this->httpRequest('/user/register', 'POST', $serialized, 'application/hal+json');
$this->httpRequest(Url::fromRoute('rest.user_registration.POST', ['_format' => 'hal_json']), 'POST', $serialized, 'application/hal+json');
}
}
@@ -1,136 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Tests user-account links.
*
* @group user
*/
class UserAccountLinksTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['menu_ui', 'block', 'test_page_test'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('system_menu_block:account');
// Make test-page default.
$this->config('system.site')->set('page.front', '/test-page')->save();
}
/**
* Tests the secondary menu.
*/
public function testSecondaryMenu() {
// Create a regular user.
$user = $this->drupalCreateUser([]);
// Log in and get the homepage.
$this->drupalLogin($user);
$this->drupalGet('<front>');
// For a logged-in user, expect the secondary menu to have links for "My
// account" and "Log out".
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', [
':menu_class' => 'menu',
':href' => 'user',
':text' => 'My account',
]);
$this->assertEqual(count($link), 1, 'My account link is in secondary menu.');
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', [
':menu_class' => 'menu',
':href' => 'user/logout',
':text' => 'Log out',
]);
$this->assertEqual(count($link), 1, 'Log out link is in secondary menu.');
// Log out and get the homepage.
$this->drupalLogout();
$this->drupalGet('<front>');
// For a logged-out user, expect the secondary menu to have a "Log in" link.
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', [
':menu_class' => 'menu',
':href' => 'user/login',
':text' => 'Log in',
]);
$this->assertEqual(count($link), 1, 'Log in link is in secondary menu.');
}
/**
* Tests disabling the 'My account' link.
*/
public function testDisabledAccountLink() {
// Create an admin user and log in.
$this->drupalLogin($this->drupalCreateUser(['access administration pages', 'administer menu']));
// Verify that the 'My account' link exists before we check for its
// disappearance.
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', [
':menu_class' => 'menu',
':href' => 'user',
':text' => 'My account',
]);
$this->assertEqual(count($link), 1, 'My account link is in the secondary menu.');
// Verify that the 'My account' link is enabled. Do not assume the value of
// auto-increment is 1. Use XPath to obtain input element id and name using
// the consistent label text.
$this->drupalGet('admin/structure/menu/manage/account');
$label = $this->xpath('//label[contains(.,:text)]/@for', [':text' => 'Enable My account menu link']);
$this->assertFieldChecked((string) $label[0], "The 'My account' link is enabled by default.");
// Disable the 'My account' link.
$edit['links[menu_plugin_id:user.page][enabled]'] = FALSE;
$this->drupalPostForm('admin/structure/menu/manage/account', $edit, t('Save'));
// Get the homepage.
$this->drupalGet('<front>');
// Verify that the 'My account' link does not appear when disabled.
$link = $this->xpath('//ul[@class=:menu_class]/li/a[contains(@href, :href) and text()=:text]', [
':menu_class' => 'menu',
':href' => 'user',
':text' => 'My account',
]);
$this->assertEqual(count($link), 0, 'My account link is not in the secondary menu.');
}
/**
* Tests page title is set correctly on user account tabs.
*/
public function testAccountPageTitles() {
// Default page titles are suffixed with the site name - Drupal.
$title_suffix = ' | Drupal';
$this->drupalGet('user');
$this->assertTitle('Log in' . $title_suffix, "Page title of /user is 'Log in'");
$this->drupalGet('user/login');
$this->assertTitle('Log in' . $title_suffix, "Page title of /user/login is 'Log in'");
$this->drupalGet('user/register');
$this->assertTitle('Create new account' . $title_suffix, "Page title of /user/register is 'Create new account' for anonymous users.");
$this->drupalGet('user/password');
$this->assertTitle('Reset your password' . $title_suffix, "Page title of /user/register is 'Reset your password' for anonymous users.");
// Check the page title for registered users is "My Account" in menus.
$this->drupalLogin($this->drupalCreateUser());
// After login, the client is redirected to /user.
$this->assertLink(t('My account'), 0, "Page title of /user is 'My Account' in menus for registered users");
$this->assertLinkByHref(\Drupal::urlGenerator()->generate('user.page'), 0);
}
}
@@ -1,95 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\simpletest\WebTestBase;
use Drupal\user\Entity\User;
/**
* Tests the user admin listing if views is not enabled.
*
* @group user
* @see user_admin_account()
*/
class UserAdminListingTest extends WebTestBase {
/**
* Tests the listing.
*/
public function testUserListing() {
$this->drupalGet('admin/people');
$this->assertResponse(403, 'Anonymous user does not have access to the user admin listing.');
// Create a bunch of users.
$accounts = [];
for ($i = 0; $i < 3; $i++) {
$account = $this->drupalCreateUser();
$accounts[$account->label()] = $account;
}
// Create a blocked user.
$account = $this->drupalCreateUser();
$account->block();
$account->save();
$accounts[$account->label()] = $account;
// Create a user at a certain timestamp.
$account = $this->drupalCreateUser();
$account->created = 1363219200;
$account->save();
$accounts[$account->label()] = $account;
$timestamp_user = $account->label();
$rid_1 = $this->drupalCreateRole([], 'custom_role_1', 'custom_role_1');
$rid_2 = $this->drupalCreateRole([], 'custom_role_2', 'custom_role_2');
$account = $this->drupalCreateUser();
$account->addRole($rid_1);
$account->addRole($rid_2);
$account->save();
$accounts[$account->label()] = $account;
$role_account_name = $account->label();
// Create an admin user and look at the listing.
$admin_user = $this->drupalCreateUser(['administer users']);
$accounts[$admin_user->label()] = $admin_user;
$accounts['admin'] = User::load(1);
$this->drupalLogin($admin_user);
$this->drupalGet('admin/people');
$this->assertResponse(200, 'The admin user has access to the user admin listing.');
$result = $this->xpath('//table[contains(@class, "responsive-enabled")]/tbody/tr');
$result_accounts = [];
foreach ($result as $account) {
$name = (string) $account->td[0]->span;
$roles = [];
if (isset($account->td[2]->div->ul)) {
foreach ($account->td[2]->div->ul->li as $element) {
$roles[] = (string) $element;
}
}
$result_accounts[$name] = [
'name' => $name,
'status' => (string) $account->td[1],
'roles' => $roles,
'member_for' => (string) $account->td[3],
'last_access' => (string) $account->td[4],
];
}
$this->assertFalse(array_keys(array_diff_key($result_accounts, $accounts)), 'Ensure all accounts are listed.');
foreach ($result_accounts as $name => $values) {
$this->assertEqual($values['status'] == t('active'), $accounts[$name]->status->value, 'Ensure the status is displayed properly.');
}
$expected_roles = ['custom_role_1', 'custom_role_2'];
$this->assertEqual($result_accounts[$role_account_name]['roles'], $expected_roles, 'Ensure roles are listed properly.');
$this->assertEqual($result_accounts[$timestamp_user]['member_for'], \Drupal::service('date.formatter')->formatTimeDiffSince($accounts[$timestamp_user]->created->value), 'Ensure the right member time is displayed.');
$this->assertEqual($result_accounts[$timestamp_user]['last_access'], 'never', 'Ensure the last access time is "never".');
}
}
@@ -1,200 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\simpletest\WebTestBase;
use Drupal\user\RoleInterface;
/**
* Tests user administration page functionality.
*
* @group user
*/
class UserAdminTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['taxonomy', 'views'];
/**
* Registers a user and deletes it.
*/
public function testUserAdmin() {
$config = $this->config('user.settings');
$user_a = $this->drupalCreateUser();
$user_a->name = 'User A';
$user_a->mail = $this->randomMachineName() . '@example.com';
$user_a->save();
$user_b = $this->drupalCreateUser(['administer taxonomy']);
$user_b->name = 'User B';
$user_b->save();
$user_c = $this->drupalCreateUser(['administer taxonomy']);
$user_c->name = 'User C';
$user_c->save();
$user_storage = $this->container->get('entity.manager')->getStorage('user');
// Create admin user to delete registered user.
$admin_user = $this->drupalCreateUser(['administer users']);
// Use a predictable name so that we can reliably order the user admin page
// by name.
$admin_user->name = 'Admin user';
$admin_user->save();
$this->drupalLogin($admin_user);
$this->drupalGet('admin/people');
$this->assertText($user_a->getUsername(), 'Found user A on admin users page');
$this->assertText($user_b->getUsername(), 'Found user B on admin users page');
$this->assertText($user_c->getUsername(), 'Found user C on admin users page');
$this->assertText($admin_user->getUsername(), 'Found Admin user on admin users page');
// Test for existence of edit link in table.
$link = $user_a->link(t('Edit'), 'edit-form', ['query' => ['destination' => $user_a->url('collection')]]);
$this->assertRaw($link, 'Found user A edit link on admin users page');
// Test exposed filter elements.
foreach (['user', 'role', 'permission', 'status'] as $field) {
$this->assertField("edit-$field", "$field exposed filter found.");
}
// Make sure the reduce duplicates element from the ManyToOneHelper is not
// displayed.
$this->assertNoField('edit-reduce-duplicates', 'Reduce duplicates form element not found in exposed filters.');
// Filter the users by name/email.
$this->drupalGet('admin/people', ['query' => ['user' => $user_a->getUsername()]]);
$result = $this->xpath('//table/tbody/tr');
$this->assertEqual(1, count($result), 'Filter by username returned the right amount.');
$this->assertEqual($user_a->getUsername(), (string) $result[0]->td[1]->span, 'Filter by username returned the right user.');
$this->drupalGet('admin/people', ['query' => ['user' => $user_a->getEmail()]]);
$result = $this->xpath('//table/tbody/tr');
$this->assertEqual(1, count($result), 'Filter by username returned the right amount.');
$this->assertEqual($user_a->getUsername(), (string) $result[0]->td[1]->span, 'Filter by username returned the right user.');
// Filter the users by permission 'administer taxonomy'.
$this->drupalGet('admin/people', ['query' => ['permission' => 'administer taxonomy']]);
// Check if the correct users show up.
$this->assertNoText($user_a->getUsername(), 'User A not on filtered by perm admin users page');
$this->assertText($user_b->getUsername(), 'Found user B on filtered by perm admin users page');
$this->assertText($user_c->getUsername(), 'Found user C on filtered by perm admin users page');
// Filter the users by role. Grab the system-generated role name for User C.
$roles = $user_c->getRoles();
unset($roles[array_search(RoleInterface::AUTHENTICATED_ID, $roles)]);
$this->drupalGet('admin/people', ['query' => ['role' => reset($roles)]]);
// Check if the correct users show up when filtered by role.
$this->assertNoText($user_a->getUsername(), 'User A not on filtered by role on admin users page');
$this->assertNoText($user_b->getUsername(), 'User B not on filtered by role on admin users page');
$this->assertText($user_c->getUsername(), 'User C on filtered by role on admin users page');
// Test blocking of a user.
$account = $user_storage->load($user_c->id());
$this->assertTrue($account->isActive(), 'User C not blocked');
$edit = [];
$edit['action'] = 'user_block_user_action';
$edit['user_bulk_form[4]'] = TRUE;
$config
->set('notify.status_blocked', TRUE)
->save();
$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']
]);
$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.');
$user_storage->resetCache([$user_c->id()]);
$account = $user_storage->load($user_c->id());
$this->assertTrue($account->isBlocked(), 'User C blocked');
// Test filtering on admin page for blocked users
$this->drupalGet('admin/people', ['query' => ['status' => 2]]);
$this->assertNoText($user_a->getUsername(), 'User A not on filtered by status on admin users page');
$this->assertNoText($user_b->getUsername(), 'User B not on filtered by status on admin users page');
$this->assertText($user_c->getUsername(), 'User C on filtered by status on admin users page');
// Test unblocking of a user from /admin/people page and sending of activation mail
$editunblock = [];
$editunblock['action'] = 'user_unblock_user_action';
$editunblock['user_bulk_form[4]'] = TRUE;
$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']
]);
$user_storage->resetCache([$user_c->id()]);
$account = $user_storage->load($user_c->id());
$this->assertTrue($account->isActive(), 'User C unblocked');
$this->assertMail("to", $account->getEmail(), "Activation mail sent to user C");
// Test blocking and unblocking another user from /user/[uid]/edit form and sending of activation mail
$user_d = $this->drupalCreateUser([]);
$user_storage->resetCache([$user_d->id()]);
$account1 = $user_storage->load($user_d->id());
$this->drupalPostForm('user/' . $account1->id() . '/edit', ['status' => 0], t('Save'));
$user_storage->resetCache([$user_d->id()]);
$account1 = $user_storage->load($user_d->id());
$this->assertTrue($account1->isBlocked(), 'User D blocked');
$this->drupalPostForm('user/' . $account1->id() . '/edit', ['status' => TRUE], t('Save'));
$user_storage->resetCache([$user_d->id()]);
$account1 = $user_storage->load($user_d->id());
$this->assertTrue($account1->isActive(), 'User D unblocked');
$this->assertMail("to", $account1->getEmail(), "Activation mail sent to user D");
}
/**
* Tests the alternate notification email address for user mails.
*/
public function testNotificationEmailAddress() {
// Test that the Notification Email address field is on the config page.
$admin_user = $this->drupalCreateUser(['administer users', 'administer account settings']);
$this->drupalLogin($admin_user);
$this->drupalGet('admin/config/people/accounts');
$this->assertRaw('id="edit-mail-notification-address"', 'Notification Email address field exists');
$this->drupalLogout();
// Test custom user registration approval email address(es).
$config = $this->config('user.settings');
// Allow users to register with admin approval.
$config
->set('verify_mail', TRUE)
->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)
->save();
// Set the site and notification email addresses.
$system = $this->config('system.site');
$server_address = $this->randomMachineName() . '@example.com';
$notify_address = $this->randomMachineName() . '@example.com';
$system
->set('mail', $server_address)
->set('mail_notification', $notify_address)
->save();
// Register a new user account.
$edit = [];
$edit['name'] = $this->randomMachineName();
$edit['mail'] = $edit['name'] . '@example.com';
$this->drupalPostForm('user/register', $edit, t('Create new account'));
$subject = 'Account details for ' . $edit['name'] . ' at ' . $system->get('name') . ' (pending admin approval)';
// Ensure that admin notification mail is sent to the configured
// Notification Email address.
$admin_mail = $this->drupalGetMails([
'to' => $notify_address,
'from' => $server_address,
'subject' => $subject,
]);
$this->assertTrue(count($admin_mail), 'New user mail to admin is sent to configured Notification Email address');
// Ensure that user notification mail is sent from the configured
// Notification Email address.
$user_mail = $this->drupalGetMails([
'to' => $edit['mail'],
'from' => $server_address,
'reply-to' => $notify_address,
'subject' => $subject,
]);
$this->assertTrue(count($user_mail), 'New user mail to user is sent from configured Notification Email address');
}
}
@@ -1,147 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\simpletest\WebTestBase;
/**
* Tests user edit page.
*
* @group user
*/
class UserEditTest extends WebTestBase {
/**
* Test user edit page.
*/
public function testUserEdit() {
// Test user edit functionality.
$user1 = $this->drupalCreateUser(['change own username']);
$user2 = $this->drupalCreateUser([]);
$this->drupalLogin($user1);
// Test that error message appears when attempting to use a non-unique user name.
$edit['name'] = $user2->getUsername();
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertRaw(t('The username %name is already taken.', ['%name' => $edit['name']]));
// Check that the default value in user name field
// 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']);
$this->drupalGet('user/' . $user1->id() . '/edit');
$this->assertFieldByName('name', $user1->getAccountName());
// Check that filling out a single password field does not validate.
$edit = [];
$edit['pass[pass1]'] = '';
$edit['pass[pass2]'] = $this->randomMachineName();
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.');
$edit['pass[pass1]'] = $this->randomMachineName();
$edit['pass[pass2]'] = '';
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.');
// Test that the error message appears when attempting to change the mail or
// pass without the current password.
$edit = [];
$edit['mail'] = $this->randomMachineName() . '@new.example.com';
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", ['%name' => t('Email')]));
$edit['current_pass'] = $user1->pass_raw;
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertRaw(t("The changes have been saved."));
// Test that the user must enter current password before changing passwords.
$edit = [];
$edit['pass[pass1]'] = $new_pass = $this->randomMachineName();
$edit['pass[pass2]'] = $new_pass;
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", ['%name' => t('Password')]));
// Try again with the current password.
$edit['current_pass'] = $user1->pass_raw;
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertRaw(t("The changes have been saved."));
// Make sure the changed timestamp is updated.
$this->assertEqual($user1->getChangedTime(), REQUEST_TIME, 'Changing a user sets "changed" timestamp.');
// Make sure the user can log in with their new password.
$this->drupalLogout();
$user1->pass_raw = $new_pass;
$this->drupalLogin($user1);
$this->drupalLogout();
// Test that the password strength indicator displays.
$config = $this->config('user.settings');
$this->drupalLogin($user1);
$config->set('password_strength', TRUE)->save();
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertRaw(t('Password strength:'), 'The password strength indicator is displayed.');
$config->set('password_strength', FALSE)->save();
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertNoRaw(t('Password strength:'), 'The password strength indicator is not displayed.');
// Check that the user status field has the correct value and that it is
// properly displayed.
$admin_user = $this->drupalCreateUser(['administer users']);
$this->drupalLogin($admin_user);
$this->drupalGet('user/' . $user1->id() . '/edit');
$this->assertNoFieldChecked('edit-status-0');
$this->assertFieldChecked('edit-status-1');
$edit = ['status' => 0];
$this->drupalPostForm('user/' . $user1->id() . '/edit', $edit, t('Save'));
$this->assertText(t('The changes have been saved.'));
$this->assertFieldChecked('edit-status-0');
$this->assertNoFieldChecked('edit-status-1');
$edit = ['status' => 1];
$this->drupalPostForm('user/' . $user1->id() . '/edit', $edit, t('Save'));
$this->assertText(t('The changes have been saved.'));
$this->assertNoFieldChecked('edit-status-0');
$this->assertFieldChecked('edit-status-1');
}
/**
* Tests setting the password to "0".
*
* We discovered in https://www.drupal.org/node/2563751 that logging in with a
* password that is literally "0" was not possible. This test ensures that
* this regression can't happen again.
*/
public function testUserWith0Password() {
$admin = $this->drupalCreateUser(['administer users']);
$this->drupalLogin($admin);
// Create a regular user.
$user1 = $this->drupalCreateUser([]);
$edit = ['pass[pass1]' => '0', 'pass[pass2]' => '0'];
$this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save'));
$this->assertRaw(t("The changes have been saved."));
}
/**
* Tests editing of a user account without an email address.
*/
public function testUserWithoutEmailEdit() {
// Test that an admin can edit users without an email address.
$admin = $this->drupalCreateUser(['administer users']);
$this->drupalLogin($admin);
// Create a regular user.
$user1 = $this->drupalCreateUser([]);
// This user has no email address.
$user1->mail = '';
$user1->save();
$this->drupalPostForm("user/" . $user1->id() . "/edit", ['mail' => ''], t('Save'));
$this->assertRaw(t("The changes have been saved."));
}
}
@@ -1,103 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\simpletest\WebTestBase;
/**
* Tests whether proper language is stored for new users and access to language
* selector.
*
* @group user
*/
class UserLanguageCreationTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['user', 'language'];
/**
* Functional test for language handling during user creation.
*/
public function testLocalUserCreation() {
// User to add and remove language and create new users.
$admin_user = $this->drupalCreateUser(['administer languages', 'access administration pages', 'administer users']);
$this->drupalLogin($admin_user);
// Add predefined language.
$langcode = 'fr';
ConfigurableLanguage::createFromLangcode($langcode)->save();
// Set language negotiation.
$edit = [
'language_interface[enabled][language-url]' => TRUE,
];
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
$this->assertText(t('Language detection configuration saved.'), 'Set language negotiation.');
// Check if the language selector is available on admin/people/create and
// set to the currently active language.
$this->drupalGet($langcode . '/admin/people/create');
$this->assertOptionSelected("edit-preferred-langcode", $langcode, 'Global language set in the language selector.');
// Create a user with the admin/people/create form and check if the correct
// language is set.
$username = $this->randomMachineName(10);
$edit = [
'name' => $username,
'mail' => $this->randomMachineName(4) . '@example.com',
'pass[pass1]' => $username,
'pass[pass2]' => $username,
];
$this->drupalPostForm($langcode . '/admin/people/create', $edit, t('Create new account'));
$user = user_load_by_name($username);
$this->assertEqual($user->getPreferredLangcode(), $langcode, 'New user has correct preferred language set.');
$this->assertEqual($user->language()->getId(), $langcode, 'New user has correct profile language set.');
// Register a new user and check if the language selector is hidden.
$this->drupalLogout();
$this->drupalGet($langcode . '/user/register');
$this->assertNoFieldByName('language[fr]', 'Language selector is not accessible.');
$username = $this->randomMachineName(10);
$edit = [
'name' => $username,
'mail' => $this->randomMachineName(4) . '@example.com',
];
$this->drupalPostForm($langcode . '/user/register', $edit, t('Create new account'));
$user = user_load_by_name($username);
$this->assertEqual($user->getPreferredLangcode(), $langcode, 'New user has correct preferred language set.');
$this->assertEqual($user->language()->getId(), $langcode, 'New user has correct profile language set.');
// Test if the admin can use the language selector and if the
// correct language is was saved.
$user_edit = $langcode . '/user/' . $user->id() . '/edit';
$this->drupalLogin($admin_user);
$this->drupalGet($user_edit);
$this->assertOptionSelected("edit-preferred-langcode", $langcode, 'Language selector is accessible and correct language is selected.');
// Set pass_raw so we can log in the new user.
$user->pass_raw = $this->randomMachineName(10);
$edit = [
'pass[pass1]' => $user->pass_raw,
'pass[pass2]' => $user->pass_raw,
];
$this->drupalPostForm($user_edit, $edit, t('Save'));
$this->drupalLogin($user);
$this->drupalGet($user_edit);
$this->assertOptionSelected("edit-preferred-langcode", $langcode, 'Language selector is accessible and correct language is selected.');
}
}
@@ -1,178 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\simpletest\WebTestBase;
use Drupal\user\Entity\User;
/**
* Ensure that login works as expected.
*
* @group user
*/
class UserLoginTest extends WebTestBase {
/**
* Tests login with destination.
*/
public function testLoginCacheTagsAndDestination() {
$this->drupalGet('user/login');
// The user login form says "Enter your <site name> username.", hence it
// depends on config:system.site, and its cache tags should be present.
$this->assertCacheTag('config:system.site');
$user = $this->drupalCreateUser([]);
$this->drupalGet('user/login', ['query' => ['destination' => 'foo']]);
$edit = ['name' => $user->getUserName(), 'pass' => $user->pass_raw];
$this->drupalPostForm(NULL, $edit, t('Log in'));
$this->assertUrl('foo', [], 'Redirected to the correct URL');
}
/**
* Test the global login flood control.
*/
public function testGlobalLoginFloodControl() {
$this->config('user.flood')
->set('ip_limit', 10)
// Set a high per-user limit out so that it is not relevant in the test.
->set('user_limit', 4000)
->save();
$user1 = $this->drupalCreateUser([]);
$incorrect_user1 = clone $user1;
$incorrect_user1->pass_raw .= 'incorrect';
// Try 2 failed logins.
for ($i = 0; $i < 2; $i++) {
$this->assertFailedLogin($incorrect_user1);
}
// A successful login will not reset the IP-based flood control count.
$this->drupalLogin($user1);
$this->drupalLogout();
// Try 8 more failed logins, they should not trigger the flood control
// mechanism.
for ($i = 0; $i < 8; $i++) {
$this->assertFailedLogin($incorrect_user1);
}
// The next login trial should result in an IP-based flood error message.
$this->assertFailedLogin($incorrect_user1, 'ip');
// A login with the correct password should also result in a flood error
// message.
$this->assertFailedLogin($user1, 'ip');
}
/**
* Test the per-user login flood control.
*/
public function testPerUserLoginFloodControl() {
$this->config('user.flood')
// Set a high global limit out so that it is not relevant in the test.
->set('ip_limit', 4000)
->set('user_limit', 3)
->save();
$user1 = $this->drupalCreateUser([]);
$incorrect_user1 = clone $user1;
$incorrect_user1->pass_raw .= 'incorrect';
$user2 = $this->drupalCreateUser([]);
// Try 2 failed logins.
for ($i = 0; $i < 2; $i++) {
$this->assertFailedLogin($incorrect_user1);
}
// A successful login will reset the per-user flood control count.
$this->drupalLogin($user1);
$this->drupalLogout();
// Try 3 failed logins for user 1, they will not trigger flood control.
for ($i = 0; $i < 3; $i++) {
$this->assertFailedLogin($incorrect_user1);
}
// Try one successful attempt for user 2, it should not trigger any
// flood control.
$this->drupalLogin($user2);
$this->drupalLogout();
// Try one more attempt for user 1, it should be rejected, even if the
// correct password has been used.
$this->assertFailedLogin($user1, 'user');
}
/**
* Test that user password is re-hashed upon login after changing $count_log2.
*/
public function testPasswordRehashOnLogin() {
// Determine default log2 for phpass hashing algorithm
$default_count_log2 = 16;
// Retrieve instance of password hashing algorithm
$password_hasher = $this->container->get('password');
// Create a new user and authenticate.
$account = $this->drupalCreateUser([]);
$password = $account->pass_raw;
$this->drupalLogin($account);
$this->drupalLogout();
// Load the stored user. The password hash should reflect $default_count_log2.
$user_storage = $this->container->get('entity.manager')->getStorage('user');
$account = User::load($account->id());
$this->assertIdentical($password_hasher->getCountLog2($account->getPassword()), $default_count_log2);
// Change the required number of iterations by loading a test-module
// containing the necessary container builder code and then verify that the
// users password gets rehashed during the login.
$overridden_count_log2 = 19;
\Drupal::service('module_installer')->install(['user_custom_phpass_params_test']);
$this->resetAll();
$account->pass_raw = $password;
$this->drupalLogin($account);
// Load the stored user, which should have a different password hash now.
$user_storage->resetCache([$account->id()]);
$account = $user_storage->load($account->id());
$this->assertIdentical($password_hasher->getCountLog2($account->getPassword()), $overridden_count_log2);
$this->assertTrue($password_hasher->check($password, $account->getPassword()));
}
/**
* Make an unsuccessful login attempt.
*
* @param \Drupal\user\Entity\User $account
* A user object with name and pass_raw attributes for the login attempt.
* @param mixed $flood_trigger
* (optional) Whether or not to expect that the flood control mechanism
* will be triggered. Defaults to NULL.
* - Set to 'user' to expect a 'too many failed logins error.
* - Set to any value to expect an error for too many failed logins per IP
* .
* - Set to NULL to expect a failed login.
*/
public function assertFailedLogin($account, $flood_trigger = NULL) {
$edit = [
'name' => $account->getUsername(),
'pass' => $account->pass_raw,
];
$this->drupalPostForm('user/login', $edit, t('Log in'));
$this->assertNoFieldByXPath("//input[@name='pass' and @value!='']", NULL, 'Password value attribute is blank.');
if (isset($flood_trigger)) {
if ($flood_trigger == 'user') {
$this->assertRaw(\Drupal::translation()->formatPlural($this->config('user.flood')->get('user_limit'), 'There has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href=":url">request a new password</a>.', 'There have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href=":url">request a new password</a>.', [':url' => \Drupal::url('user.pass')]));
}
else {
// No uid, so the limit is IP-based.
$this->assertRaw(t('Too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href=":url">request a new password</a>.', [':url' => \Drupal::url('user.pass')]));
}
}
else {
$this->assertText(t('Unrecognized username or password. Forgot your password?'));
}
}
}
@@ -118,7 +118,7 @@ class UserPasswordResetTest extends PageCacheTagsTestBase {
// invalidate the reset token.
$image = current($this->drupalGetTestFiles('image'));
$edit = [
'files[user_picture_0]' => drupal_realpath($image->uri),
'files[user_picture_0]' => \Drupal::service('file_system')->realpath($image->uri),
];
$this->drupalPostAjaxForm(NULL, $edit, 'user_picture_0_upload_button');
@@ -1,167 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\simpletest\WebTestBase;
use Drupal\user\RoleInterface;
use Drupal\user\Entity\Role;
/**
* Verify that role permissions can be added and removed via the permissions
* page.
*
* @group user
*/
class UserPermissionsTest extends WebTestBase {
/**
* User with admin privileges.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* User's role ID.
*
* @var string
*/
protected $rid;
protected function setUp() {
parent::setUp();
$this->adminUser = $this->drupalCreateUser(['administer permissions', 'access user profiles', 'administer site configuration', 'administer modules', 'administer account settings']);
// Find the new role ID.
$all_rids = $this->adminUser->getRoles();
unset($all_rids[array_search(RoleInterface::AUTHENTICATED_ID, $all_rids)]);
$this->rid = reset($all_rids);
}
/**
* Test changing user permissions through the permissions page.
*/
public function testUserPermissionChanges() {
$permissions_hash_generator = $this->container->get('user_permissions_hash_generator');
$storage = $this->container->get('entity.manager')->getStorage('user_role');
// Create an additional role and mark it as admin role.
Role::create(['is_admin' => TRUE, 'id' => 'administrator', 'label' => 'Administrator'])->save();
$storage->resetCache();
$this->drupalLogin($this->adminUser);
$rid = $this->rid;
$account = $this->adminUser;
$previous_permissions_hash = $permissions_hash_generator->generate($account);
$this->assertIdentical($previous_permissions_hash, $permissions_hash_generator->generate($this->loggedInUser));
// Add a permission.
$this->assertFalse($account->hasPermission('administer users'), 'User does not have "administer users" permission.');
$edit = [];
$edit[$rid . '[administer users]'] = TRUE;
$this->drupalPostForm('admin/people/permissions', $edit, t('Save permissions'));
$this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
$storage->resetCache();
$this->assertTrue($account->hasPermission('administer users'), 'User now has "administer users" permission.');
$current_permissions_hash = $permissions_hash_generator->generate($account);
$this->assertIdentical($current_permissions_hash, $permissions_hash_generator->generate($this->loggedInUser));
$this->assertNotEqual($previous_permissions_hash, $current_permissions_hash, 'Permissions hash has changed.');
$previous_permissions_hash = $current_permissions_hash;
// Remove a permission.
$this->assertTrue($account->hasPermission('access user profiles'), 'User has "access user profiles" permission.');
$edit = [];
$edit[$rid . '[access user profiles]'] = FALSE;
$this->drupalPostForm('admin/people/permissions', $edit, t('Save permissions'));
$this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
$storage->resetCache();
$this->assertFalse($account->hasPermission('access user profiles'), 'User no longer has "access user profiles" permission.');
$current_permissions_hash = $permissions_hash_generator->generate($account);
$this->assertIdentical($current_permissions_hash, $permissions_hash_generator->generate($this->loggedInUser));
$this->assertNotEqual($previous_permissions_hash, $current_permissions_hash, 'Permissions hash has changed.');
// Ensure that the admin role doesn't have any checkboxes.
$this->drupalGet('admin/people/permissions');
foreach (array_keys($this->container->get('user.permissions')->getPermissions()) as $permission) {
$this->assertNoFieldByName('administrator[' . $permission . ']');
}
}
/**
* Test assigning of permissions for the administrator role.
*/
public function testAdministratorRole() {
$this->drupalLogin($this->adminUser);
$this->drupalGet('admin/config/people/accounts');
// Verify that the administration role is none by default.
$this->assertOptionSelected('edit-user-admin-role', '', 'Administration role defaults to none.');
$this->assertFalse(Role::load($this->rid)->isAdmin());
// Set the user's role to be the administrator role.
$edit = [];
$edit['user_admin_role'] = $this->rid;
$this->drupalPostForm('admin/config/people/accounts', $edit, t('Save configuration'));
\Drupal::entityManager()->getStorage('user_role')->resetCache();
$this->assertTrue(Role::load($this->rid)->isAdmin());
// Enable aggregator module and ensure the 'administer news feeds'
// permission is assigned by default.
\Drupal::service('module_installer')->install(['aggregator']);
$this->assertTrue($this->adminUser->hasPermission('administer news feeds'), 'The permission was automatically assigned to the administrator role');
// Ensure that selecting '- None -' removes the admin role.
$edit = [];
$edit['user_admin_role'] = '';
$this->drupalPostForm('admin/config/people/accounts', $edit, t('Save configuration'));
\Drupal::entityManager()->getStorage('user_role')->resetCache();
\Drupal::configFactory()->reset();
$this->assertFalse(Role::load($this->rid)->isAdmin());
// Manually create two admin roles, in that case the single select should be
// hidden.
Role::create(['id' => 'admin_role_0', 'is_admin' => TRUE, 'label' => 'Admin role 0'])->save();
Role::create(['id' => 'admin_role_1', 'is_admin' => TRUE, 'label' => 'Admin role 1'])->save();
$this->drupalGet('admin/config/people/accounts');
$this->assertNoFieldByName('user_admin_role');
}
/**
* Verify proper permission changes by user_role_change_permissions().
*/
public function testUserRoleChangePermissions() {
$permissions_hash_generator = $this->container->get('user_permissions_hash_generator');
$rid = $this->rid;
$account = $this->adminUser;
$previous_permissions_hash = $permissions_hash_generator->generate($account);
// Verify current permissions.
$this->assertFalse($account->hasPermission('administer users'), 'User does not have "administer users" permission.');
$this->assertTrue($account->hasPermission('access user profiles'), 'User has "access user profiles" permission.');
$this->assertTrue($account->hasPermission('administer site configuration'), 'User has "administer site configuration" permission.');
// Change permissions.
$permissions = [
'administer users' => 1,
'access user profiles' => 0,
];
user_role_change_permissions($rid, $permissions);
// Verify proper permission changes.
$this->assertTrue($account->hasPermission('administer users'), 'User now has "administer users" permission.');
$this->assertFalse($account->hasPermission('access user profiles'), 'User no longer has "access user profiles" permission.');
$this->assertTrue($account->hasPermission('administer site configuration'), 'User still has "administer site configuration" permission.');
// Verify the permissions hash has changed.
$current_permissions_hash = $permissions_hash_generator->generate($account);
$this->assertNotEqual($previous_permissions_hash, $current_permissions_hash, 'Permissions hash has changed.');
}
}
@@ -1,149 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\image\Entity\ImageStyle;
use Drupal\simpletest\WebTestBase;
use Drupal\file\Entity\File;
/**
* Tests user picture functionality.
*
* @group user
*/
class UserPictureTest extends WebTestBase {
/**
* The profile to install as a basis for testing.
*
* Using the standard profile to test user picture config provided by the
* standard profile.
*
* @var string
*/
protected $profile = 'standard';
/**
* A regular user.
*
* @var \Drupal\user\UserInterface
*/
protected $webUser;
protected function setUp() {
parent::setUp();
// This test expects unused managed files to be marked temporary and then
// cleaned up by file_cron().
$this->config('file.settings')
->set('make_unused_managed_files_temporary', TRUE)
->save();
$this->webUser = $this->drupalCreateUser([
'access content',
'access comments',
'post comments',
'skip comment approval',
]);
}
/**
* Tests creation, display, and deletion of user pictures.
*/
public function testCreateDeletePicture() {
$this->drupalLogin($this->webUser);
// Save a new picture.
$image = current($this->drupalGetTestFiles('image'));
$file = $this->saveUserPicture($image);
// Verify that the image is displayed on the user account page.
$this->drupalGet('user');
$this->assertRaw(file_uri_target($file->getFileUri()), 'User picture found on user account page.');
// Delete the picture.
$edit = [];
$this->drupalPostForm('user/' . $this->webUser->id() . '/edit', $edit, t('Remove'));
$this->drupalPostForm(NULL, [], t('Save'));
// Call file_cron() to clean up the file. Make sure the timestamp
// of the file is older than the system.file.temporary_maximum_age
// configuration value.
db_update('file_managed')
->fields([
'changed' => REQUEST_TIME - ($this->config('system.file')->get('temporary_maximum_age') + 1),
])
->condition('fid', $file->id())
->execute();
\Drupal::service('cron')->run();
// Verify that the image has been deleted.
$this->assertFalse(File::load($file->id()), 'File was removed from the database.');
// Clear out PHP's file stat cache so we see the current value.
clearstatcache(TRUE, $file->getFileUri());
$this->assertFalse(is_file($file->getFileUri()), 'File was removed from the file system.');
}
/**
* Tests embedded users on node pages.
*/
public function testPictureOnNodeComment() {
$this->drupalLogin($this->webUser);
// Save a new picture.
$image = current($this->drupalGetTestFiles('image'));
$file = $this->saveUserPicture($image);
$node = $this->drupalCreateNode(['type' => 'article']);
// Enable user pictures on nodes.
$this->config('system.theme.global')->set('features.node_user_picture', TRUE)->save();
$image_style_id = $this->config('core.entity_view_display.user.user.compact')->get('content.user_picture.settings.image_style');
$style = ImageStyle::load($image_style_id);
$image_url = file_url_transform_relative($style->buildUrl($file->getfileUri()));
$alt_text = 'Profile picture for user ' . $this->webUser->getUsername();
// Verify that the image is displayed on the node page.
$this->drupalGet('node/' . $node->id());
$elements = $this->cssSelect('.node__meta .field--name-user-picture img[alt="' . $alt_text . '"][src="' . $image_url . '"]');
$this->assertEqual(count($elements), 1, 'User picture with alt text found on node page.');
// Enable user pictures on comments, instead of nodes.
$this->config('system.theme.global')
->set('features.node_user_picture', FALSE)
->set('features.comment_user_picture', TRUE)
->save();
$edit = [
'comment_body[0][value]' => $this->randomString(),
];
$this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit, t('Save'));
$elements = $this->cssSelect('.comment__meta .field--name-user-picture img[alt="' . $alt_text . '"][src="' . $image_url . '"]');
$this->assertEqual(count($elements), 1, 'User picture with alt text found on the comment.');
// Disable user pictures on comments and nodes.
$this->config('system.theme.global')
->set('features.node_user_picture', FALSE)
->set('features.comment_user_picture', FALSE)
->save();
$this->drupalGet('node/' . $node->id());
$this->assertNoRaw(file_uri_target($file->getFileUri()), 'User picture not found on node and comment.');
}
/**
* Edits the user picture for the test user.
*/
public function saveUserPicture($image) {
$edit = ['files[user_picture_0]' => drupal_realpath($image->uri)];
$this->drupalPostForm('user/' . $this->webUser->id() . '/edit', $edit, t('Save'));
// Load actual user data from database.
$user_storage = $this->container->get('entity.manager')->getStorage('user');
$user_storage->resetCache([$this->webUser->id()]);
$account = $user_storage->load($this->webUser->id());
return File::load($account->user_picture->target_id);
}
}
@@ -1,132 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\simpletest\WebTestBase;
use Drupal\user\Entity\Role;
use Drupal\user\RoleInterface;
/**
* Tests adding, editing and deleting user roles and changing role weights.
*
* @group user
*/
class UserRoleAdminTest extends WebTestBase {
/**
* User with admin privileges.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
/**
* Modules to enable.
*
* @var string[]
*/
public static $modules = ['block'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->adminUser = $this->drupalCreateUser(['administer permissions', 'administer users']);
$this->drupalPlaceBlock('local_tasks_block');
}
/**
* Test adding, renaming and deleting roles.
*/
public function testRoleAdministration() {
$this->drupalLogin($this->adminUser);
$default_langcode = \Drupal::languageManager()->getDefaultLanguage()->getId();
// Test presence of tab.
$this->drupalGet('admin/people/permissions');
$tabs = $this->xpath('//ul[@class=:classes and //a[contains(., :text)]]', [
':classes' => 'tabs primary',
':text' => t('Roles'),
]);
$this->assertEqual(count($tabs), 1, 'Found roles tab');
// Test adding a role. (In doing so, we use a role name that happens to
// correspond to an integer, to test that the role administration pages
// correctly distinguish between role names and IDs.)
$role_name = '123';
$edit = ['label' => $role_name, 'id' => $role_name];
$this->drupalPostForm('admin/people/roles/add', $edit, t('Save'));
$this->assertRaw(t('Role %label has been added.', ['%label' => 123]));
$role = Role::load($role_name);
$this->assertTrue(is_object($role), 'The role was successfully retrieved from the database.');
// Check that the role was created in site default language.
$this->assertEqual($role->language()->getId(), $default_langcode);
// Try adding a duplicate role.
$this->drupalPostForm('admin/people/roles/add', $edit, t('Save'));
$this->assertRaw(t('The machine-readable name is already in use. It must be unique.'), 'Duplicate role warning displayed.');
// Test renaming a role.
$role_name = '456';
$edit = ['label' => $role_name];
$this->drupalPostForm("admin/people/roles/manage/{$role->id()}", $edit, t('Save'));
$this->assertRaw(t('Role %label has been updated.', ['%label' => $role_name]));
\Drupal::entityManager()->getStorage('user_role')->resetCache([$role->id()]);
$new_role = Role::load($role->id());
$this->assertEqual($new_role->label(), $role_name, 'The role name has been successfully changed.');
// Test deleting a role.
$this->drupalGet("admin/people/roles/manage/{$role->id()}");
$this->clickLink(t('Delete'));
$this->drupalPostForm(NULL, [], t('Delete'));
$this->assertRaw(t('The role %label has been deleted.', ['%label' => $role_name]));
$this->assertNoLinkByHref("admin/people/roles/manage/{$role->id()}", 'Role edit link removed.');
\Drupal::entityManager()->getStorage('user_role')->resetCache([$role->id()]);
$this->assertFalse(Role::load($role->id()), 'A deleted role can no longer be loaded.');
// Make sure that the system-defined roles can be edited via the user
// interface.
$this->drupalGet('admin/people/roles/manage/' . RoleInterface::ANONYMOUS_ID);
$this->assertResponse(200, 'Access granted when trying to edit the built-in anonymous role.');
$this->assertNoText(t('Delete role'), 'Delete button for the anonymous role is not present.');
$this->drupalGet('admin/people/roles/manage/' . RoleInterface::AUTHENTICATED_ID);
$this->assertResponse(200, 'Access granted when trying to edit the built-in authenticated role.');
$this->assertNoText(t('Delete role'), 'Delete button for the authenticated role is not present.');
}
/**
* Test user role weight change operation and ordering.
*/
public function testRoleWeightOrdering() {
$this->drupalLogin($this->adminUser);
$roles = user_roles();
$weight = count($roles);
$new_role_weights = [];
$saved_rids = [];
// Change the role weights to make the roles in reverse order.
$edit = [];
foreach ($roles as $role) {
$edit['entities[' . $role->id() . '][weight]'] = $weight;
$new_role_weights[$role->id()] = $weight;
$saved_rids[] = $role->id();
$weight--;
}
$this->drupalPostForm('admin/people/roles', $edit, t('Save'));
$this->assertText(t('The role settings have been updated.'), 'The role settings form submitted successfully.');
// Load up the user roles with the new weights.
drupal_static_reset('user_roles');
$roles = user_roles();
$rids = [];
// Test that the role weights have been correctly saved.
foreach ($roles as $role) {
$this->assertEqual($role->getWeight(), $new_role_weights[$role->id()]);
$rids[] = $role->id();
}
// The order of the roles should be reversed.
$this->assertIdentical($rids, array_reverse($saved_rids));
}
}
@@ -1,95 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\Core\Datetime\Entity\DateFormat;
use Drupal\simpletest\WebTestBase;
/**
* Set a user time zone and verify that dates are displayed in local time.
*
* @group user
*/
class UserTimeZoneTest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['node', 'system_test'];
/**
* Tests the display of dates and time when user-configurable time zones are set.
*/
public function testUserTimeZone() {
// Setup date/time settings for Los Angeles time.
$this->config('system.date')
->set('timezone.user.configurable', 1)
->set('timezone.default', 'America/Los_Angeles')
->save();
// Load the 'medium' date format, which is the default for node creation
// time, and override it. Since we are testing time zones with Daylight
// Saving Time, and need to future proof against changes to the zoneinfo
// database, we choose the 'I' format placeholder instead of a
// human-readable zone name. With 'I', a 1 means the date is in DST, and 0
// if not.
DateFormat::load('medium')
->setPattern('Y-m-d H:i I')
->save();
// Create a user account and login.
$web_user = $this->drupalCreateUser();
$this->drupalLogin($web_user);
// Create some nodes with different authored-on dates.
// Two dates in PST (winter time):
$date1 = '2007-03-09 21:00:00 -0800';
$date2 = '2007-03-11 01:00:00 -0800';
// One date in PDT (summer time):
$date3 = '2007-03-20 21:00:00 -0700';
$this->drupalCreateContentType(['type' => 'article']);
$node1 = $this->drupalCreateNode(['created' => strtotime($date1), 'type' => 'article']);
$node2 = $this->drupalCreateNode(['created' => strtotime($date2), 'type' => 'article']);
$node3 = $this->drupalCreateNode(['created' => strtotime($date3), 'type' => 'article']);
// Confirm date format and time zone.
$this->drupalGet('node/' . $node1->id());
$this->assertText('2007-03-09 21:00 0', 'Date should be PST.');
$this->drupalGet('node/' . $node2->id());
$this->assertText('2007-03-11 01:00 0', 'Date should be PST.');
$this->drupalGet('node/' . $node3->id());
$this->assertText('2007-03-20 21:00 1', 'Date should be PDT.');
// Change user time zone to Santiago time.
$edit = [];
$edit['mail'] = $web_user->getEmail();
$edit['timezone'] = 'America/Santiago';
$this->drupalPostForm("user/" . $web_user->id() . "/edit", $edit, t('Save'));
$this->assertText(t('The changes have been saved.'), 'Time zone changed to Santiago time.');
// Confirm date format and time zone.
$this->drupalGet('node/' . $node1->id());
$this->assertText('2007-03-10 02:00 1', 'Date should be Chile summer time; five hours ahead of PST.');
$this->drupalGet('node/' . $node2->id());
$this->assertText('2007-03-11 05:00 0', 'Date should be Chile time; four hours ahead of PST');
$this->drupalGet('node/' . $node3->id());
$this->assertText('2007-03-21 00:00 0', 'Date should be Chile time; three hours ahead of PDT.');
// Ensure that anonymous users also use the default timezone.
$this->drupalLogout();
$this->drupalGet('node/' . $node1->id());
$this->assertText('2007-03-09 21:00 0', 'Date should be PST.');
$this->drupalGet('node/' . $node2->id());
$this->assertText('2007-03-11 01:00 0', 'Date should be PST.');
$this->drupalGet('node/' . $node3->id());
$this->assertText('2007-03-20 21:00 1', 'Date should be PDT.');
// Format a date without accessing the current user at all and
// ensure that it uses the default timezone.
$this->drupalGet('/system-test/date');
$this->assertText('2016-01-13 08:29 0', 'Date should be PST.');
}
}
@@ -1,78 +0,0 @@
<?php
namespace Drupal\user\Tests;
use Drupal\content_translation\Tests\ContentTranslationUITestBase;
/**
* Tests the User Translation UI.
*
* @group user
*/
class UserTranslationUITest extends ContentTranslationUITestBase {
/**
* The user name of the test user.
*
* @var string
*/
protected $name;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['language', 'content_translation', 'user', 'views'];
protected function setUp() {
$this->entityTypeId = 'user';
$this->testLanguageSelector = FALSE;
$this->name = $this->randomMachineName();
parent::setUp();
\Drupal::entityManager()->getStorage('user')->resetCache();
}
/**
* {@inheritdoc}
*/
protected function getTranslatorPermissions() {
return array_merge(parent::getTranslatorPermissions(), ['administer users']);
}
/**
* {@inheritdoc}
*/
protected function getNewEntityValues($langcode) {
// User name is not translatable hence we use a fixed value.
return ['name' => $this->name] + parent::getNewEntityValues($langcode);
}
/**
* {@inheritdoc}
*/
protected function doTestTranslationEdit() {
$storage = $this->container->get('entity_type.manager')
->getStorage($this->entityTypeId);
$storage->resetCache([$this->entityId]);
$entity = $storage->load($this->entityId);
$languages = $this->container->get('language_manager')->getLanguages();
foreach ($this->langcodes as $langcode) {
// We only want to test the title for non-english translations.
if ($langcode != 'en') {
$options = ['language' => $languages[$langcode]];
$url = $entity->urlInfo('edit-form', $options);
$this->drupalGet($url);
$title = t('@title [%language translation]', [
'@title' => $entity->getTranslation($langcode)->label(),
'%language' => $languages[$langcode]->getName(),
]);
$this->assertRaw($title);
}
}
}
}
@@ -1,67 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\user\Plugin\views\access\Permission;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Views;
/**
* Tests views perm access plugin.
*
* @group user
* @see \Drupal\user\Plugin\views\access\Permission
*/
class AccessPermissionTest extends AccessTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_access_perm'];
/**
* Tests perm access plugin.
*/
public function testAccessPerm() {
$view = Views::getView('test_access_perm');
$view->setDisplay();
$access_plugin = $view->display_handler->getPlugin('access');
$this->assertTrue($access_plugin instanceof Permission, 'Make sure the right class got instantiated.');
$this->assertEqual($access_plugin->pluginTitle(), t('Permission'));
$this->assertFalse($view->display_handler->access($this->webUser));
$this->assertTrue($view->display_handler->access($this->normalUser));
}
/**
* Tests access on render caching.
*/
public function testRenderCaching() {
$view = Views::getView('test_access_perm');
$display = &$view->storage->getDisplay('default');
$display['display_options']['cache'] = [
'type' => 'tag',
];
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
/** @var \Drupal\Core\Session\AccountSwitcherInterface $account_switcher */
$account_switcher = \Drupal::service('account_switcher');
// First access as user without access.
$build = DisplayPluginBase::buildBasicRenderable('test_access_perm', 'default');
$account_switcher->switchTo($this->normalUser);
$result = $renderer->renderPlain($build);
$this->assertNotEqual($result, '');
// Then with access.
$build = DisplayPluginBase::buildBasicRenderable('test_access_perm', 'default');
$account_switcher->switchTo($this->webUser);
$result = $renderer->renderPlain($build);
$this->assertEqual($result, '');
}
}
@@ -1,137 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\Core\Cache\Cache;
use Drupal\user\Plugin\views\access\Role;
use Drupal\views\Plugin\views\display\DisplayPluginBase;
use Drupal\views\Views;
/**
* Tests views role access plugin.
*
* @group user
* @see \Drupal\user\Plugin\views\access\Role
*/
class AccessRoleTest extends AccessTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_access_role'];
/**
* Tests role access plugin.
*/
public function testAccessRole() {
/** @var \Drupal\views\ViewEntityInterface $view */
$view = \Drupal::entityManager()->getStorage('view')->load('test_access_role');
$display = &$view->getDisplay('default');
$display['display_options']['access']['options']['role'] = [
$this->normalRole => $this->normalRole,
];
$view->save();
$this->container->get('router.builder')->rebuildIfNeeded();
$expected = [
'config' => ['user.role.' . $this->normalRole],
'module' => ['user'],
];
$this->assertIdentical($expected, $view->calculateDependencies()->getDependencies());
$executable = Views::executableFactory()->get($view);
$executable->setDisplay('page_1');
$access_plugin = $executable->display_handler->getPlugin('access');
$this->assertTrue($access_plugin instanceof Role, 'Make sure the right class got instantiated.');
// Test the access() method on the access plugin.
$this->assertFalse($executable->display_handler->access($this->webUser));
$this->assertTrue($executable->display_handler->access($this->normalUser));
$this->drupalLogin($this->webUser);
$this->drupalGet('test-role');
$this->assertResponse(403);
$this->assertCacheContext('user.roles');
$this->drupalLogin($this->normalUser);
$this->drupalGet('test-role');
$this->assertResponse(200);
$this->assertCacheContext('user.roles');
// Test allowing multiple roles.
$view = Views::getView('test_access_role')->storage;
$display = &$view->getDisplay('default');
$display['display_options']['access']['options']['role'] = [
$this->normalRole => $this->normalRole,
'anonymous' => 'anonymous',
];
$view->save();
$this->container->get('router.builder')->rebuildIfNeeded();
// Ensure that the list of roles is sorted correctly, if the generated role
// ID comes before 'anonymous', see https://www.drupal.org/node/2398259.
$roles = ['user.role.anonymous', 'user.role.' . $this->normalRole];
sort($roles);
$expected = [
'config' => $roles,
'module' => ['user'],
];
$this->assertIdentical($expected, $view->calculateDependencies()->getDependencies());
$this->drupalLogin($this->webUser);
$this->drupalGet('test-role');
$this->assertResponse(403);
$this->assertCacheContext('user.roles');
$this->drupalLogout();
$this->drupalGet('test-role');
$this->assertResponse(200);
$this->assertCacheContext('user.roles');
$this->drupalLogin($this->normalUser);
$this->drupalGet('test-role');
$this->assertResponse(200);
$this->assertCacheContext('user.roles');
}
/**
* Tests access on render caching.
*/
public function testRenderCaching() {
$view = Views::getView('test_access_role');
$display = &$view->storage->getDisplay('default');
$display['display_options']['cache'] = [
'type' => 'tag',
];
$display['display_options']['access']['options']['role'] = [
$this->normalRole => $this->normalRole,
];
$view->save();
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
/** @var \Drupal\Core\Session\AccountSwitcherInterface $account_switcher */
$account_switcher = \Drupal::service('account_switcher');
// First access as user with access.
$build = DisplayPluginBase::buildBasicRenderable('test_access_role', 'default');
$account_switcher->switchTo($this->normalUser);
$result = $renderer->renderPlain($build);
$this->assertTrue(in_array('user.roles', $build['#cache']['contexts']));
$this->assertEqual(['config:views.view.test_access_role'], $build['#cache']['tags']);
$this->assertEqual(Cache::PERMANENT, $build['#cache']['max-age']);
$this->assertNotEqual($result, '');
// Then without access.
$build = DisplayPluginBase::buildBasicRenderable('test_access_role', 'default');
$account_switcher->switchTo($this->webUser);
$result = $renderer->renderPlain($build);
// @todo Fix this in https://www.drupal.org/node/2551037,
// DisplayPluginBase::applyDisplayCacheabilityMetadata() is not invoked when
// using buildBasicRenderable() and a Views access plugin returns FALSE.
// $this->assertTrue(in_array('user.roles', $build['#cache']['contexts']));
// $this->assertEqual([], $build['#cache']['tags']);
$this->assertEqual(Cache::PERMANENT, $build['#cache']['max-age']);
$this->assertEqual($result, '');
}
}
@@ -1,66 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
/**
* A common test base class for the user access plugin tests.
*/
abstract class AccessTestBase extends UserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['block'];
/**
* Contains a user object that has no special permissions.
*
* @var \Drupal\user\UserInterface
*/
protected $webUser;
/**
* Contains a user object that has the 'views_test_data test permission'.
*
* @var \Drupal\user\UserInterface
*/
protected $normalUser;
/**
* Contains a role ID that is used by the webUser.
*
* @var string
*/
protected $webRole;
/**
* Contains a role ID that is used by the normalUser.
*
* @var string
*/
protected $normalRole;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->drupalPlaceBlock('system_breadcrumb_block');
$this->enableViewsTestModule();
$this->webUser = $this->drupalCreateUser();
$roles = $this->webUser->getRoles();
$this->webRole = $roles[0];
$this->normalRole = $this->drupalCreateRole([]);
$this->normalUser = $this->drupalCreateUser(['views_test_data test permission']);
$this->normalUser->addRole($this->normalRole);
$this->normalUser->save();
// @todo when all the plugin information is cached make a reset function and
// call it here.
}
}
@@ -1,36 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\views\Views;
/**
* Tests views user argument default plugin.
*
* @group user
*/
class ArgumentDefaultTest extends UserTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_plugin_argument_default_current_user'];
public function test_plugin_argument_default_current_user() {
// Create a user to test.
$account = $this->drupalCreateUser();
// Switch the user.
\Drupal::service('account_switcher')->switchTo($account);
$view = Views::getView('test_plugin_argument_default_current_user');
$view->initHandlers();
$this->assertEqual($view->argument['null']->getDefaultArgument(), $account->id(), 'Uid of the current user is used.');
// Switch back.
\Drupal::service('account_switcher')->switchBack();
}
}
@@ -1,74 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\Core\Form\FormState;
use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
use Drupal\views\Views;
/**
* Tests user argument validators for ID and name.
*
* @group user
*/
class ArgumentValidateTest extends UserTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_view_argument_validate_user', 'test_view_argument_validate_username'];
/**
* A user for this test.
*
* @var \Drupal\user\UserInterface
*/
protected $account;
protected function setUp() {
parent::setUp();
$this->account = $this->drupalCreateUser();
}
/**
* Tests the User (ID) argument validator.
*/
public function testArgumentValidateUserUid() {
$account = $this->account;
$view = Views::getView('test_view_argument_validate_user');
$this->executeView($view);
$this->assertTrue($view->argument['null']->validateArgument($account->id()));
// Reset argument validation.
$view->argument['null']->argument_validated = NULL;
// Fail for a valid numeric, but for a user that doesn't exist
$this->assertFalse($view->argument['null']->validateArgument(32));
$form = [];
$form_state = new FormState();
$view->argument['null']->buildOptionsForm($form, $form_state);
$sanitized_id = ArgumentPluginBase::encodeValidatorId('entity:user');
$this->assertTrue($form['validate']['options'][$sanitized_id]['roles']['#states']['visible'][':input[name="options[validate][options][' . $sanitized_id . '][restrict_roles]"]']['checked']);
}
/**
* Tests the UserName argument validator.
*/
public function testArgumentValidateUserName() {
$account = $this->account;
$view = Views::getView('test_view_argument_validate_username');
$this->executeView($view);
$this->assertTrue($view->argument['null']->validateArgument($account->getUsername()));
// Reset argument validation.
$view->argument['null']->argument_validated = NULL;
// Fail for a valid string, but for a user that doesn't exist
$this->assertFalse($view->argument['null']->validateArgument($this->randomMachineName()));
}
}
@@ -1,132 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\user\Entity\User;
/**
* Tests if entity access is respected on a user bulk form.
*
* @group user
* @see \Drupal\user\Plugin\views\field\UserBulkForm
* @see \Drupal\user\Tests\Views\BulkFormTest
*/
class BulkFormAccessTest 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_bulk_form'];
/**
* Tests if users that may not be edited, can not be edited in bulk.
*/
public function testUserEditAccess() {
// Create an authenticated user.
$no_edit_user = $this->drupalCreateUser([], 'no_edit');
// Ensure this account is not blocked.
$this->assertFalse($no_edit_user->isBlocked(), 'The user is not blocked.');
// Log in as user admin.
$admin_user = $this->drupalCreateUser(['administer users']);
$this->drupalLogin($admin_user);
// Ensure that the account "no_edit" can not be edited.
$this->drupalGet('user/' . $no_edit_user->id() . '/edit');
$this->assertFalse($no_edit_user->access('update', $admin_user));
$this->assertResponse(403, 'The user may not be edited.');
// Test blocking the account "no_edit".
$edit = [
'user_bulk_form[' . ($no_edit_user->id() - 1) . ']' => TRUE,
'action' => 'user_block_user_action',
];
$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.', [
'%action' => 'Block the selected user(s)',
'@entity_type_label' => 'User',
'%entity_label' => $no_edit_user->label(),
]));
// Re-load the account "no_edit" and ensure it is not blocked.
$no_edit_user = User::load($no_edit_user->id());
$this->assertFalse($no_edit_user->isBlocked(), 'The user is not blocked.');
// Create a normal user which can be edited by the admin user
$normal_user = $this->drupalCreateUser();
$this->assertTrue($normal_user->access('update', $admin_user));
$edit = [
'user_bulk_form[' . ($normal_user->id() - 1) . ']' => TRUE,
'action' => 'user_block_user_action',
];
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply to selected items'));
$normal_user = User::load($normal_user->id());
$this->assertTrue($normal_user->isBlocked(), 'The user is blocked.');
// Log in as user without the 'administer users' permission.
$this->drupalLogin($this->drupalCreateUser());
$edit = [
'user_bulk_form[' . ($normal_user->id() - 1) . ']' => TRUE,
'action' => 'user_unblock_user_action',
];
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply to selected items'));
// Re-load the normal user and ensure it is still blocked.
$normal_user = User::load($normal_user->id());
$this->assertTrue($normal_user->isBlocked(), 'The user is still blocked.');
}
/**
* Tests if users that may not be deleted, can not be deleted in bulk.
*/
public function testUserDeleteAccess() {
// Create two authenticated users.
$account = $this->drupalCreateUser([], 'no_delete');
$account2 = $this->drupalCreateUser([], 'may_delete');
// Log in as user admin.
$this->drupalLogin($this->drupalCreateUser(['administer users']));
// Ensure that the account "no_delete" can not be deleted.
$this->drupalGet('user/' . $account->id() . '/cancel');
$this->assertResponse(403, 'The user "no_delete" may not be deleted.');
// Ensure that the account "may_delete" *can* be deleted.
$this->drupalGet('user/' . $account2->id() . '/cancel');
$this->assertResponse(200, 'The user "may_delete" may be deleted.');
// Test deleting the accounts "no_delete" and "may_delete".
$edit = [
'user_bulk_form[' . ($account->id() - 1) . ']' => TRUE,
'user_bulk_form[' . ($account2->id() - 1) . ']' => TRUE,
'action' => 'user_cancel_user_action',
];
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply to selected items'));
$edit = [
'user_cancel_method' => 'user_cancel_delete',
];
$this->drupalPostForm(NULL, $edit, t('Cancel accounts'));
// Ensure the account "no_delete" still exists.
$account = User::load($account->id());
$this->assertNotNull($account, 'The user "no_delete" is not deleted.');
// Ensure the account "may_delete" no longer exists.
$account = User::load($account2->id());
$this->assertNull($account, 'The user "may_delete" is deleted.');
}
}
@@ -1,140 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\user\Entity\User;
use Drupal\user\RoleInterface;
use Drupal\views\Views;
/**
* Tests a user bulk form.
*
* @group user
* @see \Drupal\user\Plugin\views\field\UserBulkForm
*/
class BulkFormTest extends UserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views_ui'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_user_bulk_form', 'test_user_bulk_form_combine_filter'];
/**
* Tests the user bulk form.
*/
public function testBulkForm() {
// Log in as a user without 'administer users'.
$this->drupalLogin($this->drupalCreateUser(['administer permissions']));
$user_storage = $this->container->get('entity.manager')->getStorage('user');
// Create an user which actually can change users.
$this->drupalLogin($this->drupalCreateUser(['administer users']));
$this->drupalGet('test-user-bulk-form');
$result = $this->cssSelect('#edit-action option');
$this->assertTrue(count($result) > 0);
// Test submitting the page with no selection.
$edit = [
'action' => 'user_block_user_action',
];
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply to selected items'));
$this->assertText(t('No users selected.'));
// Assign a role to a user.
$account = $user_storage->load($this->users[0]->id());
$roles = user_role_names(TRUE);
unset($roles[RoleInterface::AUTHENTICATED_ID]);
$role = key($roles);
$this->assertFalse($account->hasRole($role), 'The user currently does not have a custom role.');
$edit = [
'user_bulk_form[1]' => TRUE,
'action' => 'user_add_role_action.' . $role,
];
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
// Re-load the user and check their roles.
$user_storage->resetCache([$account->id()]);
$account = $user_storage->load($account->id());
$this->assertTrue($account->hasRole($role), 'The user now has the custom role.');
$edit = [
'user_bulk_form[1]' => TRUE,
'action' => 'user_remove_role_action.' . $role,
];
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
// Re-load the user and check their roles.
$user_storage->resetCache([$account->id()]);
$account = $user_storage->load($account->id());
$this->assertFalse($account->hasRole($role), 'The user no longer has the custom role.');
// Block a user using the bulk form.
$this->assertTrue($account->isActive(), 'The user is not blocked.');
$this->assertRaw($account->label(), 'The user is found in the table.');
$edit = [
'user_bulk_form[1]' => TRUE,
'action' => 'user_block_user_action',
];
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
// Re-load the user and check their status.
$user_storage->resetCache([$account->id()]);
$account = $user_storage->load($account->id());
$this->assertTrue($account->isBlocked(), 'The user is blocked.');
$this->assertNoRaw($account->label(), 'The user is not found in the table.');
// Remove the user status filter from the view.
$view = Views::getView('test_user_bulk_form');
$view->removeHandler('default', 'filter', 'status');
$view->storage->save();
// Ensure the anonymous user is found.
$this->drupalGet('test-user-bulk-form');
$this->assertText($this->config('user.settings')->get('anonymous'));
// Attempt to block the anonymous user.
$edit = [
'user_bulk_form[0]' => TRUE,
'action' => 'user_block_user_action',
];
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
$anonymous_account = $user_storage->load(0);
$this->assertTrue($anonymous_account->isBlocked(), 'Ensure the anonymous user got blocked.');
// Test the list of available actions with a value that contains a dot.
$this->drupalLogin($this->drupalCreateUser(['administer permissions', 'administer views', 'administer users']));
$action_id = 'user_add_role_action.' . $role;
$edit = [
'options[include_exclude]' => 'exclude',
"options[selected_actions][$action_id]" => $action_id,
];
$this->drupalPostForm('admin/structure/views/nojs/handler/test_user_bulk_form/default/field/user_bulk_form', $edit, t('Apply'));
$this->drupalPostForm(NULL, [], t('Save'));
$this->drupalGet('test-user-bulk-form');
$this->assertNoOption('edit-action', $action_id);
$edit['options[include_exclude]'] = 'include';
$this->drupalPostForm('admin/structure/views/nojs/handler/test_user_bulk_form/default/field/user_bulk_form', $edit, t('Apply'));
$this->drupalPostForm(NULL, [], t('Save'));
$this->drupalGet('test-user-bulk-form');
$this->assertOption('edit-action', $action_id);
}
/**
* Tests the user bulk form with a combined field filter on the bulk column.
*/
public function testBulkFormCombineFilter() {
// Add a user.
User::load($this->users[0]->id());
$view = Views::getView('test_user_bulk_form_combine_filter');
$errors = $view->validate();
$this->assertEqual(reset($errors['default']), t('Field %field set in %filter is not usable for this filter type. Combined field filter only works for simple fields.', ['%field' => 'User: Bulk update', '%filter' => 'Global: Combine fields filter']));
}
}
@@ -1,68 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\views\Tests\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
/**
* Tests the permission field handler ui.
*
* @group user
* @see \Drupal\user\Plugin\views\filter\Permissions
*/
class FilterPermissionUiTest extends ViewTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_filter_permission'];
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['user', 'user_test_views', 'views_ui'];
protected function setUp() {
parent::setUp(TRUE);
ViewTestData::createTestViews(get_class($this), ['user_test_views']);
$this->enableViewsTestModule();
}
/**
* Tests basic filter handler settings in the UI.
*/
public function testHandlerUI() {
$this->drupalLogin($this->drupalCreateUser(['administer views', 'administer users']));
$this->drupalGet('admin/structure/views/view/test_filter_permission/edit/default');
// Verify that the handler summary is correctly displaying the selected
// permission.
$this->assertLink('User: Permission (= View user information)');
$this->drupalPostForm(NULL, [], 'Save');
// Verify that we can save the view.
$this->assertNoText('No valid values found on filter: User: Permission.');
$this->assertText('The view test_filter_permission has been saved.');
// Verify that the handler summary is also correct when multiple values are
// selected in the filter.
$edit = [
'options[value][]' => [
'access user profiles',
'administer views',
],
];
$this->drupalPostForm('admin/structure/views/nojs/handler/test_filter_permission/default/filter/permission', $edit, 'Apply');
$this->assertLink('User: Permission (or View us…)');
$this->drupalPostForm(NULL, [], 'Save');
// Verify that we can save the view.
$this->assertNoText('No valid values found on filter: User: Permission.');
$this->assertText('The view test_filter_permission has been saved.');
}
}
@@ -1,55 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\views\Views;
/**
* Tests the handler of the user: uid Argument.
*
* @group user
*/
class HandlerArgumentUserUidTest extends UserTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_user_uid_argument'];
/**
* Tests the generated title of an user: uid argument.
*/
public function testArgumentTitle() {
$view = Views::getView('test_user_uid_argument');
// Tests an invalid user uid.
$this->executeView($view, [rand(1000, 10000)]);
$this->assertFalse($view->getTitle());
$view->destroy();
// Tests a valid user.
$account = $this->drupalCreateUser();
$this->executeView($view, [$account->id()]);
$this->assertEqual($view->getTitle(), $account->label());
$view->destroy();
// Tests the anonymous user.
$anonymous = $this->config('user.settings')->get('anonymous');
$this->executeView($view, [0]);
$this->assertEqual($view->getTitle(), $anonymous);
$view->destroy();
$view->getDisplay()->getHandler('argument', 'uid')->options['break_phrase'] = TRUE;
$this->executeView($view, [$account->id() . ',0']);
$this->assertEqual($view->getTitle(), $account->label() . ', ' . $anonymous);
$view->destroy();
$view->getDisplay()->getHandler('argument', 'uid')->options['break_phrase'] = TRUE;
$this->executeView($view, ['0,' . $account->id()]);
$this->assertEqual($view->getTitle(), $anonymous . ', ' . $account->label());
$view->destroy();
}
}
@@ -1,46 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\Component\Utility\Html;
use Drupal\user\Entity\User;
/**
* Tests the handler of the user: role field.
*
* @group user
* @see views_handler_field_user_name
*/
class HandlerFieldRoleTest extends UserTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_views_handler_field_role'];
public function testRole() {
// Create a couple of roles for the view.
$rolename_a = 'a' . $this->randomMachineName(8);
$this->drupalCreateRole(['access content'], $rolename_a, '<em>' . $rolename_a . '</em>', 9);
$rolename_b = 'b' . $this->randomMachineName(8);
$this->drupalCreateRole(['access content'], $rolename_b, $rolename_b, 8);
$rolename_not_assigned = $this->randomMachineName(8);
$this->drupalCreateRole(['access content'], $rolename_not_assigned, $rolename_not_assigned);
// Add roles to user 1.
$user = User::load(1);
$user->addRole($rolename_a);
$user->addRole($rolename_b);
$user->save();
$this->drupalLogin($this->createUser(['access user profiles']));
$this->drupalGet('/test-views-handler-field-role');
$this->assertText($rolename_b . Html::escape('<em>' . $rolename_a . '</em>'), 'View test_views_handler_field_role renders role assigned to user in the correct order and markup in role names is escaped.');
$this->assertNoText($rolename_not_assigned, 'View test_views_handler_field_role does not render a role not assigned to a user.');
}
}
@@ -1,81 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\Core\Render\RenderContext;
use Drupal\views\Views;
/**
* Tests the handler of the user: name field.
*
* @group user
* @see views_handler_field_user_name
*/
class HandlerFieldUserNameTest extends UserTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_views_handler_field_user_name'];
public function testUserName() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$new_user = $this->drupalCreateUser(['access user profiles']);
$this->drupalLogin($new_user);
// Set defaults.
$view = Views::getView('test_views_handler_field_user_name');
$view->initHandlers();
$view->field['name']->options['link_to_user'] = TRUE;
$view->field['name']->options['type'] = 'user_name';
$view->field['name']->init($view, $view->getDisplay('default'));
$view->field['name']->options['id'] = 'name';
$this->executeView($view);
$anon_name = $this->config('user.settings')->get('anonymous');
$view->result[0]->_entity->setUsername('');
$view->result[0]->_entity->uid->value = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertTrue(strpos($render, $anon_name) !== FALSE, 'For user 0 it should use the default anonymous name by default.');
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $new_user) {
return $view->field['name']->advancedRender($view->result[$new_user->id()]);
});
$this->assertTrue(strpos($render, $new_user->getDisplayName()) !== FALSE, 'If link to user is checked the username should be part of the output.');
$this->assertTrue(strpos($render, 'user/' . $new_user->id()) !== FALSE, 'If link to user is checked the link to the user should appear as well.');
$view->field['name']->options['link_to_user'] = FALSE;
$view->field['name']->options['type'] = 'string';
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view, $new_user) {
return $view->field['name']->advancedRender($view->result[$new_user->id()]);
});
$this->assertEqual($render, $new_user->getDisplayName(), 'If the user is not linked the username should be printed out for a normal user.');
}
/**
* Tests that the field handler works when no additional fields are added.
*/
public function testNoAdditionalFields() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_views_handler_field_user_name');
$this->executeView($view);
$username = $this->randomMachineName();
$view->result[0]->_entity->setUsername($username);
$view->result[0]->_entity->uid->value = 1;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
$this->assertTrue(strpos($render, $username) !== FALSE, 'If link to user is checked the username should be part of the output.');
}
}
@@ -1,184 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\views\Views;
use Drupal\views\Tests\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
/**
* Tests the handler of the user: name filter.
*
* @group user
* @see Views\user\Plugin\views\filter\Name
*/
class HandlerFilterUserNameTest extends ViewTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views_ui', 'user_test_views'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_user_name'];
/**
* Accounts used by this test.
*
* @var array
*/
protected $accounts = [];
/**
* Usernames of $accounts.
*
* @var array
*/
protected $names = [];
/**
* Stores the column map for this testCase.
*
* @var array
*/
public $columnMap = [
'uid' => 'uid',
];
protected function setUp() {
parent::setUp();
ViewTestData::createTestViews(get_class($this), ['user_test_views']);
$this->enableViewsTestModule();
$this->accounts = [];
$this->names = [];
for ($i = 0; $i < 3; $i++) {
$this->accounts[] = $account = $this->drupalCreateUser();
$this->names[] = $account->label();
}
}
/**
* Tests just using the filter.
*/
public function testUserNameApi() {
$view = Views::getView('test_user_name');
$view->initHandlers();
$view->filter['uid']->value = [$this->accounts[0]->id()];
$this->executeView($view);
$this->assertIdenticalResultset($view, [['uid' => $this->accounts[0]->id()]], $this->columnMap);
$this->assertEqual($view->filter['uid']->getValueOptions(), NULL);
}
/**
* Tests using the user interface.
*/
public function testAdminUserInterface() {
$admin_user = $this->drupalCreateUser(['administer views', 'administer site configuration']);
$this->drupalLogin($admin_user);
$path = 'admin/structure/views/nojs/handler/test_user_name/default/filter/uid';
$this->drupalGet($path);
// Pass in an invalid username, the validation should catch it.
$users = [$this->randomMachineName()];
$users = array_map('strtolower', $users);
$edit = [
'options[value]' => implode(', ', $users)
];
$this->drupalPostForm($path, $edit, t('Apply'));
$this->assertRaw(t('There are no entities matching "%value".', ['%value' => implode(', ', $users)]));
// Pass in an invalid username and a valid username.
$random_name = $this->randomMachineName();
$users = [$random_name, $this->names[0]];
$users = array_map('strtolower', $users);
$edit = [
'options[value]' => implode(', ', $users)
];
$users = [$users[0]];
$this->drupalPostForm($path, $edit, t('Apply'));
$this->assertRaw(t('There are no entities matching "%value".', ['%value' => implode(', ', $users)]));
// Pass in just valid usernames.
$users = $this->names;
$users = array_map('strtolower', $users);
$edit = [
'options[value]' => implode(', ', $users)
];
$this->drupalPostForm($path, $edit, t('Apply'));
$this->assertNoRaw(t('There are no entities matching "%value".', ['%value' => implode(', ', $users)]));
}
/**
* Tests exposed filters.
*/
public function testExposedFilter() {
$path = 'test_user_name';
$options = [];
// Pass in an invalid username, the validation should catch it.
$users = [$this->randomMachineName()];
$users = array_map('strtolower', $users);
$options['query']['uid'] = implode(', ', $users);
$this->drupalGet($path, $options);
$this->assertRaw(t('There are no entities matching "%value".', ['%value' => implode(', ', $users)]));
// Pass in an invalid target_id in for the entity_autocomplete value format.
// There should be no errors, but all results should be returned as the
// default value for the autocomplete will not match any users so should
// be empty.
$options['query']['uid'] = [['target_id' => 9999]];
$this->drupalGet($path, $options);
// The actual result should contain all of the user ids.
foreach ($this->accounts as $account) {
$this->assertRaw($account->id());
}
// Pass in an invalid username and a valid username.
$users = [$this->randomMachineName(), $this->names[0]];
$users = array_map('strtolower', $users);
$options['query']['uid'] = implode(', ', $users);
$users = [$users[0]];
$this->drupalGet($path, $options);
$this->assertRaw(t('There are no entities matching "%value".', ['%value' => implode(', ', $users)]));
// Pass in just valid usernames.
$users = $this->names;
$options['query']['uid'] = implode(', ', $users);
$this->drupalGet($path, $options);
$this->assertNoRaw('Unable to find user');
// The actual result should contain all of the user ids.
foreach ($this->accounts as $account) {
$this->assertRaw($account->id());
}
// Pass in just valid user IDs in the entity_autocomplete target_id format.
$options['query']['uid'] = array_map(function ($account) {
return ['target_id' => $account->id()];
}, $this->accounts);
$this->drupalGet($path, $options);
$this->assertNoRaw('Unable to find user');
// The actual result should contain all of the user ids.
foreach ($this->accounts as $account) {
$this->assertRaw($account->id());
}
}
}
@@ -1,41 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\views\Views;
/**
* Tests the representative node relationship for users.
*
* @group user
*/
class RelationshipRepresentativeNodeTest extends UserTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_groupwise_user'];
/**
* Tests the relationship.
*/
public function testRelationship() {
$view = Views::getView('test_groupwise_user');
$this->executeView($view);
$map = ['node_field_data_users_field_data_nid' => 'nid', 'uid' => 'uid'];
$expected_result = [
[
'uid' => $this->users[1]->id(),
'nid' => $this->nodes[1]->id(),
],
[
'uid' => $this->users[0]->id(),
'nid' => $this->nodes[0]->id(),
],
];
$this->assertIdenticalResultset($view, $expected_result, $map);
}
}
@@ -1,33 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
/**
* Tests the handler of the user: roles argument.
*
* @group user
* @see \Drupal\user\Plugin\views\argument\RolesRid
*/
class RolesRidArgumentTest extends UserTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_user_roles_rid'];
/**
* Tests the generated title of a user: roles argument.
*/
public function testArgumentTitle() {
$role_id = $this->createRole([], 'markup_role_name', '<em>Role name with markup</em>');
$user = $this->createUser();
$user->addRole($role_id);
$user->save();
$this->drupalGet('/user_roles_rid_test/markup_role_name');
$this->assertEscaped('<em>Role name with markup</em>');
}
}
@@ -1,50 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\views\Tests\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
/**
* Tests the changed field.
*
* @group user
*/
class UserChangedTest extends ViewTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['views_ui', 'user_test_views'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_user_changed'];
protected function setUp() {
parent::setUp();
ViewTestData::createTestViews(get_class($this), ['user_test_views']);
$this->enableViewsTestModule();
}
/**
* Tests changed field.
*/
public function testChangedField() {
$path = 'test_user_changed';
$options = [];
$this->drupalGet($path, $options);
$this->assertText(t('Updated date') . ': ' . date('Y-m-d', REQUEST_TIME));
}
}
@@ -1,50 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\views\Views;
/**
* Tests the user data service field handler.
*
* @group user
* @see \Drupal\user\Plugin\views\field\UserData
*/
class UserDataTest extends UserTestBase {
/**
* Provides the user data service object.
*
* @var \Drupal\user\UserDataInterface
*/
protected $userData;
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_user_data'];
/**
* Tests field handler.
*/
public function testDataField() {
// But some random values into the user data service.
$this->userData = $this->container->get('user.data');
$random_value = $this->randomMachineName();
$this->userData->set('views_test_config', $this->users[0]->id(), 'test_value_name', $random_value);
$view = Views::getView('test_user_data');
$this->executeView($view);
$output = $view->field['data']->render($view->result[0]);
$this->assertEqual($output, $random_value, 'A valid user data got rendered.');
$view->field['data']->options['data_name'] = $this->randomMachineName();
$output = $view->field['data']->render($view->result[0]);
$this->assertFalse($output, 'An invalid configuration does not return anything');
}
}
@@ -1,46 +0,0 @@
<?php
namespace Drupal\user\Tests\Views;
use Drupal\views\Tests\ViewTestBase;
use Drupal\views\Tests\ViewTestData;
use Drupal\user\Entity\User;
/**
* @todo.
*/
abstract class UserTestBase extends ViewTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['user_test_views', 'node'];
/**
* Users to use during this test.
*
* @var array
*/
protected $users = [];
/**
* Nodes to use during this test.
*
* @var array
*/
protected $nodes = [];
protected function setUp() {
parent::setUp();
ViewTestData::createTestViews(get_class($this), ['user_test_views']);
$this->users[] = $this->drupalCreateUser();
$this->users[] = User::load(1);
$this->nodes[] = $this->drupalCreateNode(['uid' => $this->users[0]->id()]);
$this->nodes[] = $this->drupalCreateNode(['uid' => 1]);
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace Drupal\user;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
use Drupal\user\Entity\User;
/**
* Defines a custom field item class for the 'timezone' user entity field.
*/
class TimeZoneItem extends StringItem {
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$timezones = User::getAllowedTimezones();
// We need to vary the selected timezones since we're generating a sample.
$key = rand(0, count($timezones) - 1);
return $timezones[$key];
}
}
@@ -0,0 +1,86 @@
<?php
namespace Drupal\user;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Url;
/**
* ToolbarLinkBuilder fills out the placeholders generated in user_toolbar().
*/
class ToolbarLinkBuilder {
use StringTranslationTrait;
/**
* The current user.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $account;
/**
* ToolbarHandler constructor.
*
* @param \Drupal\Core\Session\AccountProxyInterface $account
* The current user.
*/
public function __construct(AccountProxyInterface $account) {
$this->account = $account;
}
/**
* Lazy builder callback for rendering toolbar links.
*
* @return array
* A renderable array as expected by the renderer service.
*/
public function renderToolbarLinks() {
$links = [
'account' => [
'title' => $this->t('View profile'),
'url' => Url::fromRoute('user.page'),
'attributes' => [
'title' => $this->t('User account'),
],
],
'account_edit' => [
'title' => $this->t('Edit profile'),
'url' => Url::fromRoute('entity.user.edit_form', ['user' => $this->account->id()]),
'attributes' => [
'title' => $this->t('Edit user account'),
],
],
'logout' => [
'title' => $this->t('Log out'),
'url' => Url::fromRoute('user.logout'),
],
];
$build = [
'#theme' => 'links__toolbar_user',
'#links' => $links,
'#attributes' => [
'class' => ['toolbar-menu'],
],
'#cache' => [
'contexts' => ['user'],
],
];
return $build;
}
/**
* Lazy builder callback for rendering the username.
*
* @return array
* A renderable array as expected by the renderer service.
*/
public function renderDisplayName() {
return [
'#markup' => $this->account->getDisplayName(),
];
}
}
@@ -58,7 +58,7 @@ class UserAccessControlHandler extends EntityAccessControlHandler {
return AccessResult::allowed()->cachePerUser();
}
else {
return AccessResultNeutral::neutral("The 'access user profiles' permission is required and the user must be active.");
return AccessResultNeutral::neutral("The 'access user profiles' permission is required and the user must be active.")->cachePerPermissions()->addCacheableDependency($entity);
}
break;
+6 -10
View File
@@ -48,30 +48,26 @@ class UserData implements UserDataInterface {
}
return NULL;
}
$return = [];
// If $module and $uid were passed, return data keyed by name.
elseif (isset($uid)) {
$return = [];
if (isset($uid)) {
foreach ($result as $record) {
$return[$record->name] = ($record->serialized ? unserialize($record->value) : $record->value);
}
return $return;
}
// If $module and $name were passed, return data keyed by uid.
elseif (isset($name)) {
$return = [];
if (isset($name)) {
foreach ($result as $record) {
$return[$record->uid] = ($record->serialized ? unserialize($record->value) : $record->value);
}
return $return;
}
// If only $module was passed, return data keyed by uid and name.
else {
$return = [];
foreach ($result as $record) {
$return[$record->uid][$record->name] = ($record->serialized ? unserialize($record->value) : $record->value);
}
return $return;
foreach ($result as $record) {
$return[$record->uid][$record->name] = ($record->serialized ? unserialize($record->value) : $record->value);
}
return $return;
}
/**
+11
View File
@@ -2,6 +2,7 @@
namespace Drupal\user;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
/**
@@ -23,4 +24,14 @@ class UserNameItem extends StringItem {
return $value === NULL || $value === '';
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition) {
$values = parent::generateSampleValue($field_definition);
// User names larger than 60 characters won't pass validation.
$values['value'] = substr($values['value'], 0, UserInterface::USERNAME_MAX_LENGTH);
return $values;
}
}
+23 -6
View File
@@ -1,8 +1,25 @@
<?php
// @codingStandardsIgnoreFile
// This class is intentionally empty so that it overwrites when sites are
// updated from a zip/tarball without deleting the /core folder first.
// @todo: remove in 8.3.x
//
namespace Drupal\user;
class UserServiceProvider {}
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
class UserServiceProvider implements ServiceModifierInterface {
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
if ($container->hasParameter('user.tempstore.expire')) {
@trigger_error('The container parameter "user.tempstore.expire" is deprecated. Use "tempstore.expire" instead. See https://www.drupal.org/node/2935639.', E_USER_DEPRECATED);
$container->setParameter('tempstore.expire', $container->getParameter('user.tempstore.expire'));
}
else {
// Ensure the user.tempstore.expire parameter is set to the same value
// for modules that still rely on it.
$container->setParameter('user.tempstore.expire', $container->getParameter('tempstore.expire'));
}
}
}
+12 -26
View File
@@ -220,34 +220,20 @@ class UserViewsData extends EntityViewsData {
],
];
$data['user__roles']['table']['group'] = $this->t('User');
// Alter the user roles target_id column.
$data['user__roles']['roles_target_id']['field']['id'] = 'user_roles';
$data['user__roles']['roles_target_id']['field']['no group by'] = TRUE;
$data['user__roles']['table']['join'] = [
'users_field_data' => [
'left_field' => 'uid',
'field' => 'entity_id',
],
];
$data['user__roles']['roles_target_id']['filter']['id'] = 'user_roles';
$data['user__roles']['roles_target_id']['filter']['allow empty'] = TRUE;
$data['user__roles']['roles_target_id'] = [
'title' => $this->t('Roles'),
'help' => $this->t('Roles that a user belongs to.'),
'field' => [
'id' => 'user_roles',
'no group by' => TRUE,
],
'filter' => [
'id' => 'user_roles',
'allow empty' => TRUE,
],
'argument' => [
'id' => 'user__roles_rid',
'name table' => 'role',
'name field' => 'name',
'empty field name' => $this->t('No role'),
'zero is null' => TRUE,
'numeric' => TRUE,
],
$data['user__roles']['roles_target_id']['argument'] = [
'id' => 'user__roles_rid',
'name table' => 'role',
'name field' => 'name',
'empty field name' => $this->t('No role'),
'zero is null' => TRUE,
'numeric' => TRUE,
];
$data['user__roles']['permission'] = [