Update to Drupal 8.2.0. For more information, see https://www.drupal.org/project/drupal/releases/8.2.0
This commit is contained in:
parent
2f563ab520
commit
f1c8716f57
1732 changed files with 52334 additions and 11780 deletions
|
@ -705,7 +705,7 @@ display:
|
|||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: true
|
||||
value: '1'
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
|
@ -753,7 +753,7 @@ display:
|
|||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: true
|
||||
value: '1'
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
|
|
|
@ -89,7 +89,7 @@ display:
|
|||
entity_field: name
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
value: '1'
|
||||
table: users_field_data
|
||||
field: status
|
||||
id: status
|
||||
|
|
|
@ -96,7 +96,7 @@ display:
|
|||
entity_field: name
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
value: '1'
|
||||
table: users_field_data
|
||||
field: status
|
||||
id: status
|
||||
|
|
|
@ -6,21 +6,38 @@ source:
|
|||
plugin: d6_user_picture_file
|
||||
constants:
|
||||
is_public: true
|
||||
# source_base_path must be set by the tool configuring this migration. It
|
||||
# represents the fully qualified path relative to which URIs in the files
|
||||
# table are specified, and must end with a /.
|
||||
source_base_path: ''
|
||||
process:
|
||||
filename: filename
|
||||
uid: uid
|
||||
uri:
|
||||
source_full_path:
|
||||
-
|
||||
plugin: concat
|
||||
delimiter: /
|
||||
source:
|
||||
- constants/source_base_path
|
||||
- picture
|
||||
-
|
||||
plugin: urlencode
|
||||
destination_full_path:
|
||||
plugin: file_uri
|
||||
source:
|
||||
- picture
|
||||
- file_directory_path
|
||||
- temp_directory_path
|
||||
- 'constants/is_public'
|
||||
uri:
|
||||
plugin: file_copy
|
||||
source:
|
||||
- '@source_full_path'
|
||||
- '@destination_full_path'
|
||||
destination:
|
||||
plugin: entity:file
|
||||
source_path_property: picture
|
||||
migration_dependencies:
|
||||
# Every migration that saves into {file_managed} must have the d6_file
|
||||
# migration as an optional dependency to ensure it runs first.
|
||||
# Every migration that references a file by Drupal 6 fid should specify d6_file as an
|
||||
# optional dependency.
|
||||
optional:
|
||||
- d6_file
|
||||
|
|
|
@ -41,3 +41,4 @@ migration_dependencies:
|
|||
- user_picture_field_instance
|
||||
- user_picture_entity_display
|
||||
- user_picture_entity_form_display
|
||||
- d7_field_instance
|
||||
|
|
|
@ -62,7 +62,7 @@ class Cookie implements AuthenticationProviderInterface {
|
|||
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
|
||||
* The session.
|
||||
*
|
||||
* @return \Drupal\Core\Session\AccountInterface|NULL
|
||||
* @return \Drupal\Core\Session\AccountInterface|null
|
||||
* The UserSession object for the current user, or NULL if this is an
|
||||
* anonymous session.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\user\Controller;
|
||||
|
||||
use Drupal\Core\Access\CsrfTokenGenerator;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Flood\FloodInterface;
|
||||
use Drupal\Core\Routing\RouteProviderInterface;
|
||||
use Drupal\user\UserAuthInterface;
|
||||
use Drupal\user\UserInterface;
|
||||
use Drupal\user\UserStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
/**
|
||||
* Provides controllers for login, login status and logout via HTTP requests.
|
||||
*/
|
||||
class UserAuthenticationController extends ControllerBase implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* String sent in responses, to describe the user as being logged in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const LOGGED_IN = 1;
|
||||
|
||||
/**
|
||||
* String sent in responses, to describe the user as being logged out.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const LOGGED_OUT = 0;
|
||||
|
||||
/**
|
||||
* The flood controller.
|
||||
*
|
||||
* @var \Drupal\Core\Flood\FloodInterface
|
||||
*/
|
||||
protected $flood;
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\user\UserStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* The CSRF token generator.
|
||||
*
|
||||
* @var \Drupal\Core\Access\CsrfTokenGenerator
|
||||
*/
|
||||
protected $csrfToken;
|
||||
|
||||
/**
|
||||
* The user authentication.
|
||||
*
|
||||
* @var \Drupal\user\UserAuthInterface
|
||||
*/
|
||||
protected $userAuth;
|
||||
|
||||
/**
|
||||
* The route provider.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteProviderInterface
|
||||
*/
|
||||
protected $routeProvider;
|
||||
|
||||
/**
|
||||
* The serializer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Serializer
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The available serialization formats.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $serializerFormats = [];
|
||||
|
||||
/**
|
||||
* Constructs a new UserAuthenticationController object.
|
||||
*
|
||||
* @param \Drupal\Core\Flood\FloodInterface $flood
|
||||
* The flood controller.
|
||||
* @param \Drupal\user\UserStorageInterface $user_storage
|
||||
* The user storage.
|
||||
* @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
|
||||
* The CSRF token generator.
|
||||
* @param \Drupal\user\UserAuthInterface $user_auth
|
||||
* The user authentication.
|
||||
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
|
||||
* The route provider.
|
||||
* @param \Symfony\Component\Serializer\Serializer $serializer
|
||||
* The serializer.
|
||||
* @param array $serializer_formats
|
||||
* The available serialization formats.
|
||||
*/
|
||||
public function __construct(FloodInterface $flood, UserStorageInterface $user_storage, CsrfTokenGenerator $csrf_token, UserAuthInterface $user_auth, RouteProviderInterface $route_provider, Serializer $serializer, array $serializer_formats) {
|
||||
$this->flood = $flood;
|
||||
$this->userStorage = $user_storage;
|
||||
$this->csrfToken = $csrf_token;
|
||||
$this->userAuth = $user_auth;
|
||||
$this->serializer = $serializer;
|
||||
$this->serializerFormats = $serializer_formats;
|
||||
$this->routeProvider = $route_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
if ($container->hasParameter('serializer.formats') && $container->has('serializer')) {
|
||||
$serializer = $container->get('serializer');
|
||||
$formats = $container->getParameter('serializer.formats');
|
||||
}
|
||||
else {
|
||||
$formats = ['json'];
|
||||
$encoders = [new JsonEncoder()];
|
||||
$serializer = new Serializer([], $encoders);
|
||||
}
|
||||
|
||||
return new static(
|
||||
$container->get('flood'),
|
||||
$container->get('entity_type.manager')->getStorage('user'),
|
||||
$container->get('csrf_token'),
|
||||
$container->get('user.auth'),
|
||||
$container->get('router.route_provider'),
|
||||
$serializer,
|
||||
$formats
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs in a user.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* A response which contains the ID and CSRF token.
|
||||
*/
|
||||
public function login(Request $request) {
|
||||
$format = $this->getRequestFormat($request);
|
||||
|
||||
$content = $request->getContent();
|
||||
$credentials = $this->serializer->decode($content, $format);
|
||||
if (!isset($credentials['name']) && !isset($credentials['pass'])) {
|
||||
throw new BadRequestHttpException('Missing credentials.');
|
||||
}
|
||||
|
||||
if (!isset($credentials['name'])) {
|
||||
throw new BadRequestHttpException('Missing credentials.name.');
|
||||
}
|
||||
if (!isset($credentials['pass'])) {
|
||||
throw new BadRequestHttpException('Missing credentials.pass.');
|
||||
}
|
||||
|
||||
$this->floodControl($request, $credentials['name']);
|
||||
|
||||
if ($this->userIsBlocked($credentials['name'])) {
|
||||
throw new BadRequestHttpException('The user has not been activated or is blocked.');
|
||||
}
|
||||
|
||||
if ($uid = $this->userAuth->authenticate($credentials['name'], $credentials['pass'])) {
|
||||
$this->flood->clear('user.http_login', $this->getLoginFloodIdentifier($request, $credentials['name']));
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = $this->userStorage->load($uid);
|
||||
$this->userLoginFinalize($user);
|
||||
|
||||
// Send basic metadata about the logged in user.
|
||||
$response_data = [];
|
||||
if ($user->get('uid')->access('view', $user)) {
|
||||
$response_data['current_user']['uid'] = $user->id();
|
||||
}
|
||||
if ($user->get('roles')->access('view', $user)) {
|
||||
$response_data['current_user']['roles'] = $user->getRoles();
|
||||
}
|
||||
if ($user->get('name')->access('view', $user)) {
|
||||
$response_data['current_user']['name'] = $user->getAccountName();
|
||||
}
|
||||
$response_data['csrf_token'] = $this->csrfToken->get('rest');
|
||||
|
||||
$logout_route = $this->routeProvider->getRouteByName('user.logout.http');
|
||||
// Trim '/' off path to match \Drupal\Core\Access\CsrfAccessCheck.
|
||||
$logout_path = ltrim($logout_route->getPath(), '/');
|
||||
$response_data['logout_token'] = $this->csrfToken->get($logout_path);
|
||||
|
||||
$encoded_response_data = $this->serializer->encode($response_data, $format);
|
||||
return new Response($encoded_response_data);
|
||||
}
|
||||
|
||||
$flood_config = $this->config('user.flood');
|
||||
if ($identifier = $this->getLoginFloodIdentifier($request, $credentials['name'])) {
|
||||
$this->flood->register('user.http_login', $flood_config->get('user_window'), $identifier);
|
||||
}
|
||||
// Always register an IP-based failed login event.
|
||||
$this->flood->register('user.failed_login_ip', $flood_config->get('ip_window'));
|
||||
throw new BadRequestHttpException('Sorry, unrecognized username or password.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the user is blocked.
|
||||
*
|
||||
* @param string $name
|
||||
* The username.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the user is blocked, otherwise FALSE.
|
||||
*/
|
||||
protected function userIsBlocked($name) {
|
||||
return user_is_blocked($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the user login.
|
||||
*
|
||||
* @param \Drupal\user\UserInterface $user
|
||||
* The user.
|
||||
*/
|
||||
protected function userLoginFinalize(UserInterface $user) {
|
||||
user_login_finalize($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs out a user.
|
||||
*
|
||||
* @return \Drupal\rest\ResourceResponse
|
||||
* The response object.
|
||||
*/
|
||||
public function logout() {
|
||||
$this->userLogout();
|
||||
return new Response(NULL, 204);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the user out.
|
||||
*/
|
||||
protected function userLogout() {
|
||||
user_logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a user is logged in or not.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* The response.
|
||||
*/
|
||||
public function loginStatus() {
|
||||
if ($this->currentUser()->isAuthenticated()) {
|
||||
$response = new Response(self::LOGGED_IN);
|
||||
}
|
||||
else {
|
||||
$response = new Response(self::LOGGED_OUT);
|
||||
}
|
||||
$response->headers->set('Content-Type', 'text/plain');
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the format of the current request.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
*
|
||||
* @return string
|
||||
* The format of the request.
|
||||
*/
|
||||
protected function getRequestFormat(Request $request) {
|
||||
$format = $request->getRequestFormat();
|
||||
if (!in_array($format, $this->serializerFormats)) {
|
||||
throw new BadRequestHttpException("Unrecognized format: $format.");
|
||||
}
|
||||
return $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enforces flood control for the current login request.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param string $username
|
||||
* The user name sent for login credentials.
|
||||
*/
|
||||
protected function floodControl(Request $request, $username) {
|
||||
$flood_config = $this->config('user.flood');
|
||||
if (!$this->flood->isAllowed('user.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) {
|
||||
throw new AccessDeniedHttpException('Access is blocked because of IP based flood prevention.', NULL, Response::HTTP_TOO_MANY_REQUESTS);
|
||||
}
|
||||
|
||||
if ($identifier = $this->getLoginFloodIdentifier($request, $username)) {
|
||||
// Don't allow login if the limit for this user has been reached.
|
||||
// Default is to allow 5 failed attempts every 6 hours.
|
||||
if (!$this->flood->isAllowed('user.http_login', $flood_config->get('user_limit'), $flood_config->get('user_window'), $identifier)) {
|
||||
if ($flood_config->get('uid_only')) {
|
||||
$error_message = sprintf('There have been more than %s failed login attempts for this account. It is temporarily blocked. Try again later or request a new password.', $flood_config->get('user_limit'));
|
||||
}
|
||||
else {
|
||||
$error_message = 'Too many failed login attempts from your IP address. This IP address is temporarily blocked.';
|
||||
}
|
||||
throw new AccessDeniedHttpException($error_message, NULL, Response::HTTP_TOO_MANY_REQUESTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the login identifier for user login flood control.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The current request.
|
||||
* @param string $username
|
||||
* The username supplied in login credentials.
|
||||
*
|
||||
* @return string
|
||||
* The login identifier or if the user does not exist an empty string.
|
||||
*/
|
||||
protected function getLoginFloodIdentifier(Request $request, $username) {
|
||||
$flood_config = $this->config('user.flood');
|
||||
$accounts = $this->userStorage->loadByProperties(['name' => $username, 'status' => 1]);
|
||||
if ($account = reset($accounts)) {
|
||||
if ($flood_config->get('uid_only')) {
|
||||
// Register flood events based on the uid only, so they apply for any
|
||||
// IP address. This is the most secure option.
|
||||
$identifier = $account->id();
|
||||
}
|
||||
else {
|
||||
// The default identifier is a combination of uid and IP address. This
|
||||
// is less secure but more resistant to denial-of-service attacks that
|
||||
// could lock out all users with public user names.
|
||||
$identifier = $account->id() . '-' . $request->getClientIp();
|
||||
}
|
||||
return $identifier;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
|
@ -425,21 +425,17 @@ class User extends ContentEntityBase implements UserInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
||||
$fields['uid'] = BaseFieldDefinition::create('integer')
|
||||
->setLabel(t('User ID'))
|
||||
->setDescription(t('The user ID.'))
|
||||
->setReadOnly(TRUE)
|
||||
->setSetting('unsigned', TRUE);
|
||||
/** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
|
||||
$fields = parent::baseFieldDefinitions($entity_type);
|
||||
|
||||
$fields['uuid'] = BaseFieldDefinition::create('uuid')
|
||||
->setLabel(t('UUID'))
|
||||
->setDescription(t('The user UUID.'))
|
||||
->setReadOnly(TRUE);
|
||||
$fields['uid']->setLabel(t('User ID'))
|
||||
->setDescription(t('The user ID.'));
|
||||
|
||||
$fields['langcode'] = BaseFieldDefinition::create('language')
|
||||
->setLabel(t('Language code'))
|
||||
$fields['uuid']->setDescription(t('The user UUID.'));
|
||||
|
||||
$fields['langcode']->setLabel(t('Language code'))
|
||||
->setDescription(t('The user language code.'))
|
||||
->setTranslatable(TRUE);
|
||||
->setDisplayOptions('form', ['type' => 'hidden']);
|
||||
|
||||
$fields['preferred_langcode'] = BaseFieldDefinition::create('language')
|
||||
->setLabel(t('Preferred language code'))
|
||||
|
|
|
@ -232,7 +232,7 @@ class UserLoginForm extends FormBase {
|
|||
// handlers that ran earlier than this one.
|
||||
$user_input = $form_state->getUserInput();
|
||||
$query = isset($user_input['name']) ? array('name' => $user_input['name']) : array();
|
||||
$form_state->setErrorByName('name', $this->t('Unrecognized username or password. <a href=":password">Have you forgotten your password?</a>', array(':password' => $this->url('user.pass', [], array('query' => $query)))));
|
||||
$form_state->setErrorByName('name', $this->t('Unrecognized username or password. <a href=":password">Forgot your password?</a>', array(':password' => $this->url('user.pass', [], array('query' => $query)))));
|
||||
$accounts = $this->userStorage->loadByProperties(array('name' => $form_state->getValue('name')));
|
||||
if (!empty($accounts)) {
|
||||
$this->logger('user')->notice('Login attempt failed for %user.', array('%user' => $form_state->getValue('name')));
|
||||
|
|
|
@ -42,7 +42,7 @@ class UserPermissionsForm extends FormBase {
|
|||
* The permission handler.
|
||||
* @param \Drupal\user\RoleStorageInterface $role_storage
|
||||
* The role storage.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(PermissionHandlerInterface $permission_handler, RoleStorageInterface $role_storage, ModuleHandlerInterface $module_handler) {
|
||||
|
@ -100,7 +100,6 @@ class UserPermissionsForm extends FormBase {
|
|||
'#value' => $role_names,
|
||||
);
|
||||
// Render role/permission overview:
|
||||
$options = array();
|
||||
$hide_descriptions = system_admin_compact_mode();
|
||||
|
||||
$form['system_compact_link'] = array(
|
||||
|
@ -145,7 +144,6 @@ class UserPermissionsForm extends FormBase {
|
|||
'restrict access' => FALSE,
|
||||
'warning' => !empty($perm_item['restrict access']) ? $this->t('Warning: Give to trusted roles only; this permission has security implications.') : '',
|
||||
);
|
||||
$options[$perm] = $perm_item['title'];
|
||||
$form['permissions'][$perm]['description'] = array(
|
||||
'#type' => 'inline_template',
|
||||
'#template' => '<div class="permission"><span class="title">{{ title }}</span>{% if description or warning %}<div class="description">{% if warning %}<em class="permission-warning">{{ warning }}</em> {% endif %}{{ description }}</div>{% endif %}</div>',
|
||||
|
@ -158,7 +156,6 @@ class UserPermissionsForm extends FormBase {
|
|||
$form['permissions'][$perm]['description']['#context']['description'] = $perm_item['description'];
|
||||
$form['permissions'][$perm]['description']['#context']['warning'] = $perm_item['warning'];
|
||||
}
|
||||
$options[$perm] = '';
|
||||
foreach ($role_names as $rid => $name) {
|
||||
$form['permissions'][$perm][$rid] = array(
|
||||
'#title' => $name . ': ' . $perm_item['title'],
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Component\Discovery\YamlDiscovery;
|
||||
use Drupal\Core\Discovery\YamlDiscovery;
|
||||
use Drupal\Core\Controller\ControllerResolverInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
|
@ -59,7 +59,7 @@ class PermissionHandler implements PermissionHandlerInterface {
|
|||
/**
|
||||
* The YAML discovery class to find all .permissions.yml files.
|
||||
*
|
||||
* @var \Drupal\Component\Discovery\YamlDiscovery
|
||||
* @var \Drupal\Core\Discovery\YamlDiscovery
|
||||
*/
|
||||
protected $yamlDiscovery;
|
||||
|
||||
|
@ -91,7 +91,7 @@ class PermissionHandler implements PermissionHandlerInterface {
|
|||
/**
|
||||
* Gets the YAML discovery.
|
||||
*
|
||||
* @return \Drupal\Component\Discovery\YamlDiscovery
|
||||
* @return \Drupal\Core\Discovery\YamlDiscovery
|
||||
* The YAML discovery.
|
||||
*/
|
||||
protected function getYamlDiscovery() {
|
||||
|
|
|
@ -29,7 +29,7 @@ class UserNameConstraintValidator extends ConstraintValidator {
|
|||
if (strpos($name, ' ') !== FALSE) {
|
||||
$this->context->addViolation($constraint->multipleSpacesMessage);
|
||||
}
|
||||
if (preg_match('/[^\x{80}-\x{F7} a-z0-9@_.\'-]/i', $name)
|
||||
if (preg_match('/[^\x{80}-\x{F7} a-z0-9@+_.\'-]/i', $name)
|
||||
|| preg_match(
|
||||
// Non-printable ISO-8859-1 + NBSP
|
||||
'/[\x{80}-\x{A0}' .
|
||||
|
|
|
@ -25,11 +25,11 @@ class UserUpdate7002 extends ProcessPluginBase implements ContainerFactoryPlugin
|
|||
*/
|
||||
protected static $timezones;
|
||||
|
||||
/**
|
||||
* Contains the system.theme configuration object.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Config
|
||||
*/
|
||||
/**
|
||||
* Contains the system.theme configuration object.
|
||||
*
|
||||
* @var \Drupal\Core\Config\Config
|
||||
*/
|
||||
protected $dateConfig;
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,7 +9,7 @@ use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
|
|||
/**
|
||||
* Default argument plugin to extract the current user
|
||||
*
|
||||
* This plugin actually has no options so it odes not need to do a great deal.
|
||||
* This plugin actually has no options so it does not need to do a great deal.
|
||||
*
|
||||
* @ViewsArgumentDefault(
|
||||
* id = "current_user",
|
||||
|
|
|
@ -112,16 +112,4 @@ class Permissions extends PrerenderList {
|
|||
return $item['permission'];
|
||||
}
|
||||
|
||||
/*
|
||||
protected function documentSelfTokens(&$tokens) {
|
||||
$tokens['[' . $this->options['id'] . '-role' . ']'] = $this->t('The name of the role.');
|
||||
$tokens['[' . $this->options['id'] . '-rid' . ']'] = $this->t('The role ID of the role.');
|
||||
}
|
||||
|
||||
protected function addSelfTokens(&$tokens, $item) {
|
||||
$tokens['[' . $this->options['id'] . '-role' . ']'] = $item['role'];
|
||||
$tokens['[' . $this->options['id'] . '-rid' . ']'] = $item['rid'];
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
|
@ -96,9 +96,9 @@ class Name extends InOperator {
|
|||
// prevent array filter from removing our anonymous user.
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValueOptions() {
|
||||
return $this->valueOptions;
|
||||
}
|
||||
|
@ -108,7 +108,8 @@ class Name extends InOperator {
|
|||
$this->valueOptions = array();
|
||||
|
||||
if ($this->value) {
|
||||
$result = entity_load_multiple_by_properties('user', array('uid' => $this->value));
|
||||
$result = \Drupal::entityTypeManager()->getStorage('user')
|
||||
->loadByProperties(['uid' => $this->value]);
|
||||
foreach ($result as $account) {
|
||||
if ($account->id()) {
|
||||
$this->valueOptions[$account->id()] = $account->label();
|
||||
|
|
|
@ -100,7 +100,7 @@ class UserAdminTest extends WebTestBase {
|
|||
$config
|
||||
->set('notify.status_blocked', TRUE)
|
||||
->save();
|
||||
$this->drupalPostForm('admin/people', $edit, t('Apply'), array(
|
||||
$this->drupalPostForm('admin/people', $edit, t('Apply to selected items'), array(
|
||||
// Sort the table by username so that we know reliably which user will be
|
||||
// targeted with the blocking action.
|
||||
'query' => array('order' => 'name', 'sort' => 'asc')
|
||||
|
@ -121,7 +121,7 @@ class UserAdminTest extends WebTestBase {
|
|||
$editunblock = array();
|
||||
$editunblock['action'] = 'user_unblock_user_action';
|
||||
$editunblock['user_bulk_form[4]'] = TRUE;
|
||||
$this->drupalPostForm('admin/people', $editunblock, t('Apply'), array(
|
||||
$this->drupalPostForm('admin/people', $editunblock, t('Apply to selected items'), array(
|
||||
// Sort the table by username so that we know reliably which user will be
|
||||
// targeted with the blocking action.
|
||||
'query' => array('order' => 'name', 'sort' => 'asc')
|
||||
|
@ -174,8 +174,8 @@ class UserAdminTest extends WebTestBase {
|
|||
->save();
|
||||
// Register a new user account.
|
||||
$edit = array();
|
||||
$edit['name'] = $name = $this->randomMachineName();
|
||||
$edit['mail'] = $mail = $edit['name'] . '@example.com';
|
||||
$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
|
||||
|
|
|
@ -34,9 +34,9 @@ class UserBlocksTest extends WebTestBase {
|
|||
$this->drupalLogout($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that user login block is hidden from user/login.
|
||||
*/
|
||||
/**
|
||||
* Tests that user login block is hidden from user/login.
|
||||
*/
|
||||
function testUserLoginBlockVisibility() {
|
||||
// Array keyed list where key being the URL address and value being expected
|
||||
// visibility as boolean type.
|
||||
|
@ -51,7 +51,7 @@ class UserBlocksTest extends WebTestBase {
|
|||
$elements = $this->xpath('//div[contains(@class,"block-user-login-block") and @role="form"]');
|
||||
if ($expected_visibility) {
|
||||
$this->assertTrue(!empty($elements), 'User login block in path "' . $path . '" should be visible');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$this->assertTrue(empty($elements), 'User login block in path "' . $path . '" should not be visible');
|
||||
}
|
||||
|
@ -87,6 +87,17 @@ class UserBlocksTest extends WebTestBase {
|
|||
$this->drupalPostForm('http://example.com/', $edit, t('Log in'), array('external' => FALSE));
|
||||
// Check that we remain on the site after login.
|
||||
$this->assertUrl($user->url('canonical', ['absolute' => TRUE]), [], 'Redirected to user profile page after login from the frontpage');
|
||||
|
||||
// Verify that form validation errors are displayed immediately for forms
|
||||
// in blocks and not on subsequent page requests.
|
||||
$this->drupalLogout();
|
||||
$edit = array();
|
||||
$edit['name'] = 'foo';
|
||||
$edit['pass'] = 'invalid password';
|
||||
$this->drupalPostForm('filter/tips', $edit, t('Log in'));
|
||||
$this->assertText(t('Unrecognized username or password. Forgot your password?'));
|
||||
$this->drupalGet('filter/tips');
|
||||
$this->assertNoText(t('Unrecognized username or password. Forgot your password?'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -124,7 +124,7 @@ class UserCancelTest extends WebTestBase {
|
|||
'action' => 'user_cancel_user_action',
|
||||
'user_bulk_form[0]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm('admin/people', $edit, t('Apply'));
|
||||
$this->drupalPostForm('admin/people', $edit, t('Apply to selected items'));
|
||||
|
||||
// Verify that uid 1's account was not cancelled.
|
||||
$user_storage->resetCache(array(1));
|
||||
|
@ -353,7 +353,7 @@ class UserCancelTest extends WebTestBase {
|
|||
$test_node = $node_storage->load($node->id());
|
||||
$this->assertTrue(($test_node->getOwnerId() == 0 && $test_node->isPublished()), 'Node of the user has been attributed to anonymous user.');
|
||||
$test_node = node_revision_load($revision, TRUE);
|
||||
$this->assertTrue(($test_node->getRevisionAuthor()->id() == 0 && $test_node->isPublished()), 'Node revision of the user has been attributed to anonymous user.');
|
||||
$this->assertTrue(($test_node->getRevisionUser()->id() == 0 && $test_node->isPublished()), 'Node revision of the user has been attributed to anonymous user.');
|
||||
$node_storage->resetCache(array($revision_node->id()));
|
||||
$test_node = $node_storage->load($revision_node->id());
|
||||
$this->assertTrue(($test_node->getOwnerId() != 0 && $test_node->isPublished()), "Current revision of the user's node was not attributed to anonymous user.");
|
||||
|
@ -567,7 +567,7 @@ class UserCancelTest extends WebTestBase {
|
|||
for ($i = 0; $i <= 4; $i++) {
|
||||
$edit['user_bulk_form[' . $i . ']'] = TRUE;
|
||||
}
|
||||
$this->drupalPostForm('admin/people', $edit, t('Apply'));
|
||||
$this->drupalPostForm('admin/people', $edit, t('Apply to selected items'));
|
||||
$this->assertText(t('Are you sure you want to cancel these user accounts?'), 'Confirmation form to cancel accounts displayed.');
|
||||
$this->assertText(t('When cancelling these accounts'), 'Allows to select account cancellation method.');
|
||||
$this->assertText(t('Require email confirmation to cancel account'), 'Allows to send confirmation mail.');
|
||||
|
|
|
@ -171,7 +171,7 @@ class UserLoginTest extends WebTestBase {
|
|||
}
|
||||
}
|
||||
else {
|
||||
$this->assertText(t('Unrecognized username or password. Have you forgotten your password?'));
|
||||
$this->assertText(t('Unrecognized username or password. Forgot your password?'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ class UserPasswordResetTest extends PageCacheTagsTestBase {
|
|||
$edit['name'] = $this->account->getUsername();
|
||||
$this->drupalPostForm(NULL, $edit, t('Submit'));
|
||||
|
||||
// Verify that the user was sent an email.
|
||||
// Verify that the user was sent an email.
|
||||
$this->assertMail('to', $this->account->getEmail(), 'Password email sent to user.');
|
||||
$subject = t('Replacement login information for @username at @site', array('@username' => $this->account->getUsername(), '@site' => $this->config('system.site')->get('name')));
|
||||
$this->assertMail('subject', $subject, 'Password reset email subject is correct.');
|
||||
|
@ -287,7 +287,7 @@ class UserPasswordResetTest extends PageCacheTagsTestBase {
|
|||
'pass' => $this->randomMachineName(),
|
||||
);
|
||||
$this->drupalPostForm('user/login', $edit, t('Log in'));
|
||||
$this->assertRaw(t('Unrecognized username or password. <a href=":password">Have you forgotten your password?</a>',
|
||||
$this->assertRaw(t('Unrecognized username or password. <a href=":password">Forgot your password?</a>',
|
||||
array(':password' => \Drupal::url('user.pass', [], array('query' => array('name' => $edit['name']))))));
|
||||
unset($edit['pass']);
|
||||
$this->drupalGet('user/password', array('query' => array('name' => $edit['name'])));
|
||||
|
@ -332,6 +332,6 @@ class UserPasswordResetTest extends PageCacheTagsTestBase {
|
|||
$this->assertNoText($user2->getUsername(), 'The invalid password reset page does not show the user name.');
|
||||
$this->assertUrl('user/password', array(), 'The user is redirected to the password reset request page.');
|
||||
$this->assertText('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,10 @@ class UserRegistrationTest extends WebTestBase {
|
|||
$edit['mail'] = $mail = $edit['name'] . '@example.com';
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->assertText(t('A welcome message with further instructions has been sent to your email address.'), 'User registered successfully.');
|
||||
$accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
|
||||
|
||||
/** @var EntityStorageInterface $storage */
|
||||
$storage = $this->container->get('entity_type.manager')->getStorage('user');
|
||||
$accounts = $storage->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertTrue($new_user->isActive(), 'New account is active after registration.');
|
||||
$resetURL = user_pass_reset_url($new_user);
|
||||
|
@ -54,7 +57,7 @@ class UserRegistrationTest extends WebTestBase {
|
|||
$edit['mail'] = $mail = $edit['name'] . '@example.com';
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->container->get('entity.manager')->getStorage('user')->resetCache();
|
||||
$accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
|
||||
$accounts = $storage->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertFalse($new_user->isActive(), 'New account is blocked until approved by an administrator.');
|
||||
}
|
||||
|
@ -83,7 +86,8 @@ class UserRegistrationTest extends WebTestBase {
|
|||
$edit['pass[pass2]'] = $new_pass;
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->container->get('entity.manager')->getStorage('user')->resetCache();
|
||||
$accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertNotNull($new_user, 'New account successfully created with matching passwords.');
|
||||
$this->assertText(t('Registration successful. You are now logged in.'), 'Users are logged in after registering.');
|
||||
|
@ -108,7 +112,8 @@ class UserRegistrationTest extends WebTestBase {
|
|||
$this->assertText(t('The username @name has not been activated or is blocked.', array('@name' => $name)), 'User cannot log in yet.');
|
||||
|
||||
// Activate the new account.
|
||||
$accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$admin_user = $this->drupalCreateUser(array('administer users'));
|
||||
$this->drupalLogin($admin_user);
|
||||
|
@ -248,7 +253,8 @@ class UserRegistrationTest extends WebTestBase {
|
|||
$this->drupalPostForm(NULL, $edit, t('Create new account'));
|
||||
|
||||
// Check user fields.
|
||||
$accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertEqual($new_user->getUsername(), $name, 'Username matches.');
|
||||
$this->assertEqual($new_user->getEmail(), $mail, 'Email address matches.');
|
||||
|
@ -338,7 +344,8 @@ class UserRegistrationTest extends WebTestBase {
|
|||
$edit['test_user_field[0][value]'] = $value;
|
||||
$this->drupalPostForm(NULL, $edit, t('Create new account'));
|
||||
// Check user fields.
|
||||
$accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertEqual($new_user->test_user_field->value, $value, 'The field value was correctly saved.');
|
||||
|
||||
|
@ -367,7 +374,8 @@ class UserRegistrationTest extends WebTestBase {
|
|||
$edit['mail'] = $mail = $edit['name'] . '@example.com';
|
||||
$this->drupalPostForm(NULL, $edit, t('Create new account'));
|
||||
// Check user fields.
|
||||
$accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(array('name' => $name, 'mail' => $mail));
|
||||
$new_user = reset($accounts);
|
||||
$this->assertEqual($new_user->test_user_field[0]->value, $value, format_string('@js : The field value was correctly saved.', array('@js' => $js)));
|
||||
$this->assertEqual($new_user->test_user_field[1]->value, $value + 1, format_string('@js : The field value was correctly saved.', array('@js' => $js)));
|
||||
|
|
|
@ -113,7 +113,7 @@ class UserRoleAdminTest extends WebTestBase {
|
|||
$saved_rids[] = $role->id();
|
||||
$weight--;
|
||||
}
|
||||
$this->drupalPostForm('admin/people/roles', $edit, t('Save order'));
|
||||
$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.
|
||||
|
|
|
@ -21,8 +21,9 @@ class UserSearchTest extends WebTestBase {
|
|||
|
||||
function testUserSearch() {
|
||||
// Verify that a user without 'administer users' permission cannot search
|
||||
// for users by email address.
|
||||
$user1 = $this->drupalCreateUser(array('access user profiles', 'search content'));
|
||||
// for users by email address. Additionally, ensure that the username has a
|
||||
// plus sign to ensure searching works with that.
|
||||
$user1 = $this->drupalCreateUser(array('access user profiles', 'search content'), "foo+bar");
|
||||
$this->drupalLogin($user1);
|
||||
$keys = $user1->getEmail();
|
||||
$edit = array('keys' => $keys);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\user\Tests;
|
||||
|
||||
use Drupal\Core\Datetime\Entity\DateFormat;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
|
@ -27,7 +28,7 @@ class UserTimeZoneTest extends WebTestBase {
|
|||
->set('timezone.user.configurable', 1)
|
||||
->set('timezone.default', 'America/Los_Angeles')
|
||||
->save();
|
||||
entity_load('date_format', 'medium')
|
||||
DateFormat::load('medium')
|
||||
->setPattern('Y-m-d H:i T')
|
||||
->save();
|
||||
|
||||
|
|
|
@ -53,7 +53,10 @@ class UserTranslationUITest extends ContentTranslationUITestBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function doTestTranslationEdit() {
|
||||
$entity = entity_load($this->entityTypeId, $this->entityId, TRUE);
|
||||
$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) {
|
||||
|
|
|
@ -50,7 +50,7 @@ class BulkFormAccessTest extends UserTestBase {
|
|||
'user_bulk_form[' . ($no_edit_user->id() - 1) . ']' => TRUE,
|
||||
'action' => 'user_block_user_action',
|
||||
);
|
||||
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply'));
|
||||
$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.', [
|
||||
|
@ -71,7 +71,7 @@ class BulkFormAccessTest extends UserTestBase {
|
|||
'user_bulk_form[' . ($normal_user->id() - 1) . ']' => TRUE,
|
||||
'action' => 'user_block_user_action',
|
||||
);
|
||||
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply'));
|
||||
$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.');
|
||||
|
@ -83,7 +83,7 @@ class BulkFormAccessTest extends UserTestBase {
|
|||
'user_bulk_form[' . ($normal_user->id() - 1) . ']' => TRUE,
|
||||
'action' => 'user_unblock_user_action',
|
||||
);
|
||||
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply'));
|
||||
$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());
|
||||
|
@ -114,7 +114,7 @@ class BulkFormAccessTest extends UserTestBase {
|
|||
'user_bulk_form[' . ($account2->id() - 1) . ']' => TRUE,
|
||||
'action' => 'user_cancel_user_action',
|
||||
);
|
||||
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply'));
|
||||
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply to selected items'));
|
||||
$edit = array(
|
||||
'user_cancel_method' => 'user_cancel_delete',
|
||||
);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\user\Tests\Views;
|
||||
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\user\RoleInterface;
|
||||
use Drupal\views\Views;
|
||||
|
||||
|
@ -45,7 +46,7 @@ class BulkFormTest extends UserTestBase {
|
|||
$edit = array(
|
||||
'action' => 'user_block_user_action',
|
||||
);
|
||||
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply'));
|
||||
$this->drupalPostForm('test-user-bulk-form', $edit, t('Apply to selected items'));
|
||||
$this->assertText(t('No users selected.'));
|
||||
|
||||
// Assign a role to a user.
|
||||
|
@ -59,7 +60,7 @@ class BulkFormTest extends UserTestBase {
|
|||
'user_bulk_form[1]' => TRUE,
|
||||
'action' => 'user_add_role_action.' . $role,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
|
||||
// Re-load the user and check their roles.
|
||||
$user_storage->resetCache(array($account->id()));
|
||||
$account = $user_storage->load($account->id());
|
||||
|
@ -69,7 +70,7 @@ class BulkFormTest extends UserTestBase {
|
|||
'user_bulk_form[1]' => TRUE,
|
||||
'action' => 'user_remove_role_action.' . $role,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
|
||||
// Re-load the user and check their roles.
|
||||
$user_storage->resetCache(array($account->id()));
|
||||
$account = $user_storage->load($account->id());
|
||||
|
@ -82,7 +83,7 @@ class BulkFormTest extends UserTestBase {
|
|||
'user_bulk_form[1]' => TRUE,
|
||||
'action' => 'user_block_user_action',
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
|
||||
// Re-load the user and check their status.
|
||||
$user_storage->resetCache(array($account->id()));
|
||||
$account = $user_storage->load($account->id());
|
||||
|
@ -103,7 +104,7 @@ class BulkFormTest extends UserTestBase {
|
|||
'user_bulk_form[0]' => TRUE,
|
||||
'action' => 'user_block_user_action',
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply'));
|
||||
$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.');
|
||||
|
||||
|
@ -130,7 +131,7 @@ class BulkFormTest extends UserTestBase {
|
|||
*/
|
||||
public function testBulkFormCombineFilter() {
|
||||
// Add a user.
|
||||
$account = entity_load('user', $this->users[0]->id());
|
||||
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.', array('%field' => 'User: Bulk update', '%filter' => 'Global: Combine fields filter')));
|
||||
|
|
|
@ -14,8 +14,8 @@ $connection = Database::getConnection();
|
|||
// already.
|
||||
$connection->delete('config')->condition('name', 'user.mail')->execute();
|
||||
$connection->insert('config')
|
||||
->fields(array('collection', 'name', 'data'))
|
||||
->values(array(
|
||||
->fields(array('collection', 'name', 'data'))
|
||||
->values(array(
|
||||
'collection' => '',
|
||||
'name' => 'user.mail',
|
||||
'data' => "a:10:{s:14:\"cancel_confirm\";a:2:{s:4:\"body\";s:369:\"[user:name],\n\nA request to cancel your account has been made at [site:name].\n\nYou may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser:\n\n[user:cancel-url]\n\nNOTE: The cancellation of your account is not reversible.\n\nThis link expires in one day and nothing will happen if it is not used.\n\n-- [site:name] team\";s:7:\"subject\";s:59:\"Account cancellation request for [user:name] at [site:name]\";}s:14:\"password_reset\";a:2:{s:4:\"body\";s:397:\"[user:name],\n\nA request to reset the password for your account has been made at [site:name].\n\nYou may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used.\n\n-- [site:name] team\";s:7:\"subject\";s:60:\"Replacement login information for [user:name] at [site:name]\";}s:22:\"register_admin_created\";a:2:{s:4:\"body\";s:463:\"[user:name],\n\nA site administrator at [site:name] has created an account for you. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team\";s:7:\"subject\";s:58:\"An administrator created an account for you at [site:name]\";}s:29:\"register_no_approval_required\";a:2:{s:4:\"body\";s:437:\"[user:name],\n\nThank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team\";s:7:\"subject\";s:46:\"Account details for [user:name] at [site:name]\";}s:25:\"register_pending_approval\";a:2:{s:4:\"body\";s:281:\"[user:name],\n\nThank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another email containing information about how to log in, set your password, and other details.\n\n\n-- [site:name] team\";s:7:\"subject\";s:71:\"Account details for [user:name] at [site:name] (pending admin approval)\";}s:31:\"register_pending_approval_admin\";a:2:{s:4:\"body\";s:56:\"[user:name] has applied for an account.\n\n[user:edit-url]\";s:7:\"subject\";s:71:\"Account details for [user:name] at [site:name] (pending admin approval)\";}s:16:\"status_activated\";a:2:{s:4:\"body\";s:446:\"[user:name],\n\nYour account at [site:name] has been activated.\n\nYou may now log in by clicking this link or copying and pasting it into your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team\";s:7:\"subject\";s:57:\"Account details for [user:name] at [site:name] (approved)\";}s:14:\"status_blocked\";a:2:{s:4:\"body\";s:89:\"[user:name],\n\nYour account on [site:account-name] has been blocked.\n\n-- [site:name] team\";s:7:\"subject\";s:56:\"Account details for [user:name] at [site:name] (blocked)\";}s:15:\"status_canceled\";a:2:{s:4:\"body\";s:82:\"[user:name],\n\nYour account on [site:name] has been canceled.\n\n-- [site:name] team\";s:7:\"subject\";s:57:\"Account details for [user:name] at [site:name] (canceled)\";}s:8:\"langcode\";s:2:\"en\";}"
|
||||
|
|
|
@ -48,7 +48,7 @@ display:
|
|||
group: 1
|
||||
id: status
|
||||
table: users_field_data
|
||||
value: true
|
||||
value: '1'
|
||||
plugin_id: boolean
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
|
|
|
@ -52,7 +52,7 @@ display:
|
|||
table: users_field_data
|
||||
field: status
|
||||
operator: '='
|
||||
value: true
|
||||
value: '1'
|
||||
plugin_id: boolean
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
|
|
|
@ -126,7 +126,7 @@ display:
|
|||
field_api_classes: false
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
value: '1'
|
||||
table: users_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
|
|
|
@ -142,7 +142,7 @@ display:
|
|||
plugin_id: user_roles
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
value: '1'
|
||||
table: users_field_data
|
||||
field: status
|
||||
id: status
|
||||
|
|
421
core/modules/user/tests/src/Functional/UserLoginHttpTest.php
Normal file
421
core/modules/user/tests/src/Functional/UserLoginHttpTest.php
Normal file
|
@ -0,0 +1,421 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Flood\DatabaseBackend;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Controller\UserAuthenticationController;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
use Symfony\Component\Serializer\Encoder\XmlEncoder;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
/**
|
||||
* Tests login via direct HTTP.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserLoginHttpTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* The cookie jar.
|
||||
*
|
||||
* @var \GuzzleHttp\Cookie\CookieJar
|
||||
*/
|
||||
protected $cookies;
|
||||
|
||||
/**
|
||||
* The serializer.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\Serializer
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->cookies = new CookieJar();
|
||||
$encoders = [new JsonEncoder(), new XmlEncoder()];
|
||||
$this->serializer = new Serializer([], $encoders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a login HTTP request.
|
||||
*
|
||||
* @param string $name
|
||||
* The username.
|
||||
* @param string $pass
|
||||
* The user password.
|
||||
* @param string $format
|
||||
* The format to use to make the request.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface The HTTP response.
|
||||
* The HTTP response.
|
||||
*/
|
||||
protected function loginRequest($name, $pass, $format = 'json') {
|
||||
$user_login_url = Url::fromRoute('user.login.http')
|
||||
->setRouteParameter('_format', $format)
|
||||
->setAbsolute();
|
||||
|
||||
$request_body = [];
|
||||
if (isset($name)) {
|
||||
$request_body['name'] = $name;
|
||||
}
|
||||
if (isset($pass)) {
|
||||
$request_body['pass'] = $pass;
|
||||
}
|
||||
|
||||
$result = \Drupal::httpClient()->post($user_login_url->toString(), [
|
||||
'body' => $this->serializer->encode($request_body, $format),
|
||||
'headers' => [
|
||||
'Accept' => "application/$format",
|
||||
],
|
||||
'http_errors' => FALSE,
|
||||
'cookies' => $this->cookies,
|
||||
]);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user session life cycle.
|
||||
*/
|
||||
public function testLogin() {
|
||||
$client = \Drupal::httpClient();
|
||||
foreach ([FALSE, TRUE] as $serialization_enabled_option) {
|
||||
if ($serialization_enabled_option) {
|
||||
/** @var \Drupal\Core\Extension\ModuleInstaller $module_installer */
|
||||
$module_installer = $this->container->get('module_installer');
|
||||
$module_installer->install(['serialization']);
|
||||
$formats = ['json', 'xml'];
|
||||
}
|
||||
else {
|
||||
// Without the serialization module only JSON is supported.
|
||||
$formats = ['json'];
|
||||
}
|
||||
foreach ($formats as $format) {
|
||||
// Create new user for each iteration to reset flood.
|
||||
// Grant the user administer users permissions to they can see the
|
||||
// 'roles' field.
|
||||
$account = $this->drupalCreateUser(['administer users']);
|
||||
$name = $account->getUsername();
|
||||
$pass = $account->passRaw;
|
||||
|
||||
$login_status_url = $this->getLoginStatusUrlString($format);
|
||||
$response = $client->get($login_status_url);
|
||||
$this->assertHttpResponse($response, 200, UserAuthenticationController::LOGGED_OUT);
|
||||
|
||||
// Flooded.
|
||||
$this->config('user.flood')
|
||||
->set('user_limit', 3)
|
||||
->save();
|
||||
|
||||
$response = $this->loginRequest($name, 'wrong-pass', $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Sorry, unrecognized username or password.', $format);
|
||||
|
||||
$response = $this->loginRequest($name, 'wrong-pass', $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Sorry, unrecognized username or password.', $format);
|
||||
|
||||
$response = $this->loginRequest($name, 'wrong-pass', $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Sorry, unrecognized username or password.', $format);
|
||||
|
||||
$response = $this->loginRequest($name, 'wrong-pass', $format);
|
||||
$this->assertHttpResponseWithMessage($response, 403, 'Too many failed login attempts from your IP address. This IP address is temporarily blocked.', $format);
|
||||
|
||||
// After testing the flood control we can increase the limit.
|
||||
$this->config('user.flood')
|
||||
->set('user_limit', 100)
|
||||
->save();
|
||||
|
||||
$response = $this->loginRequest(NULL, NULL, $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Missing credentials.', $format);
|
||||
|
||||
$response = $this->loginRequest(NULL, $pass, $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Missing credentials.name.', $format);
|
||||
|
||||
$response = $this->loginRequest($name, NULL, $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Missing credentials.pass.', $format);
|
||||
|
||||
// Blocked.
|
||||
$account
|
||||
->block()
|
||||
->save();
|
||||
|
||||
$response = $this->loginRequest($name, $pass, $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'The user has not been activated or is blocked.', $format);
|
||||
|
||||
$account
|
||||
->activate()
|
||||
->save();
|
||||
|
||||
$response = $this->loginRequest($name, 'garbage', $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Sorry, unrecognized username or password.', $format);
|
||||
|
||||
$response = $this->loginRequest('garbage', $pass, $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Sorry, unrecognized username or password.', $format);
|
||||
|
||||
$response = $this->loginRequest($name, $pass, $format);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$result_data = $this->serializer->decode($response->getBody(), $format);
|
||||
$this->assertEquals($name, $result_data['current_user']['name']);
|
||||
$this->assertEquals($account->id(), $result_data['current_user']['uid']);
|
||||
$this->assertEquals($account->getRoles(), $result_data['current_user']['roles']);
|
||||
$logout_token = $result_data['logout_token'];
|
||||
|
||||
$response = $client->get($login_status_url, ['cookies' => $this->cookies]);
|
||||
$this->assertHttpResponse($response, 200, UserAuthenticationController::LOGGED_IN);
|
||||
|
||||
$response = $this->logoutRequest($format, $logout_token);
|
||||
$this->assertEquals(204, $response->getStatusCode());
|
||||
|
||||
$response = $client->get($login_status_url, ['cookies' => $this->cookies]);
|
||||
$this->assertHttpResponse($response, 200, UserAuthenticationController::LOGGED_OUT);
|
||||
|
||||
$this->resetFlood();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value for a given key from the response.
|
||||
*
|
||||
* @param \Psr\Http\Message\ResponseInterface $response
|
||||
* The response object.
|
||||
* @param string $key
|
||||
* The key for the value.
|
||||
* @param string $format
|
||||
* The encoded format.
|
||||
*
|
||||
* @return mixed
|
||||
* The value for the key.
|
||||
*/
|
||||
protected function getResultValue(ResponseInterface $response, $key, $format) {
|
||||
$decoded = $this->serializer->decode((string) $response->getBody(), $format);
|
||||
if (is_array($decoded)) {
|
||||
return $decoded[$key];
|
||||
}
|
||||
else {
|
||||
return $decoded->{$key};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all flood entries.
|
||||
*/
|
||||
protected function resetFlood() {
|
||||
$this->container->get('database')->delete(DatabaseBackend::TABLE_NAME)->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the global login flood control.
|
||||
*
|
||||
* @see \Drupal\basic_auth\Tests\Authentication\BasicAuthTest::testGlobalLoginFloodControl
|
||||
* @see \Drupal\user\Tests\UserLoginTest::testGlobalLoginFloodControl
|
||||
*/
|
||||
public function testGlobalLoginFloodControl() {
|
||||
$this->config('user.flood')
|
||||
->set('ip_limit', 2)
|
||||
// Set a high per-user limit out so that it is not relevant in the test.
|
||||
->set('user_limit', 4000)
|
||||
->save();
|
||||
|
||||
$user = $this->drupalCreateUser([]);
|
||||
$incorrect_user = clone $user;
|
||||
$incorrect_user->passRaw .= 'incorrect';
|
||||
|
||||
// Try 2 failed logins.
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$response = $this->loginRequest($incorrect_user->getUsername(), $incorrect_user->passRaw);
|
||||
$this->assertEquals('400', $response->getStatusCode());
|
||||
}
|
||||
|
||||
// IP limit has reached to its limit. Even valid user credentials will fail.
|
||||
$response = $this->loginRequest($user->getUsername(), $user->passRaw);
|
||||
$this->assertHttpResponseWithMessage($response, '403', 'Access is blocked because of IP based flood prevention.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a response for status code and body.
|
||||
*
|
||||
* @param \Psr\Http\Message\ResponseInterface $response
|
||||
* The response object.
|
||||
* @param int $expected_code
|
||||
* The expected status code.
|
||||
* @param mixed $expected_body
|
||||
* The expected response body.
|
||||
*/
|
||||
protected function assertHttpResponse(ResponseInterface $response, $expected_code, $expected_body) {
|
||||
$this->assertEquals($expected_code, $response->getStatusCode());
|
||||
$this->assertEquals($expected_body, (string) $response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a response for status code and message.
|
||||
*
|
||||
* @param \Psr\Http\Message\ResponseInterface $response
|
||||
* The response object.
|
||||
* @param int $expected_code
|
||||
* The expected status code.
|
||||
* @param string $expected_message
|
||||
* The expected message encoded in response.
|
||||
* @param string $format
|
||||
* The format that the response is encoded in.
|
||||
*/
|
||||
protected function assertHttpResponseWithMessage(ResponseInterface $response, $expected_code, $expected_message, $format = 'json') {
|
||||
$this->assertEquals($expected_code, $response->getStatusCode());
|
||||
$this->assertEquals($expected_message, $this->getResultValue($response, 'message', $format));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the per-user login flood control.
|
||||
*
|
||||
* @see \Drupal\user\Tests\UserLoginTest::testPerUserLoginFloodControl
|
||||
* @see \Drupal\basic_auth\Tests\Authentication\BasicAuthTest::testPerUserLoginFloodControl
|
||||
*/
|
||||
public function testPerUserLoginFloodControl() {
|
||||
foreach ([TRUE, FALSE] as $uid_only_setting) {
|
||||
$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)
|
||||
->set('uid_only', $uid_only_setting)
|
||||
->save();
|
||||
|
||||
$user1 = $this->drupalCreateUser([]);
|
||||
$incorrect_user1 = clone $user1;
|
||||
$incorrect_user1->passRaw .= 'incorrect';
|
||||
|
||||
$user2 = $this->drupalCreateUser([]);
|
||||
|
||||
// Try 2 failed logins.
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$response = $this->loginRequest($incorrect_user1->getUsername(), $incorrect_user1->passRaw);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Sorry, unrecognized username or password.');
|
||||
}
|
||||
|
||||
// A successful login will reset the per-user flood control count.
|
||||
$response = $this->loginRequest($user1->getUsername(), $user1->passRaw);
|
||||
$result_data = $this->serializer->decode($response->getBody(), 'json');
|
||||
$this->logoutRequest('json', $result_data['logout_token']);
|
||||
|
||||
// Try 3 failed logins for user 1, they will not trigger flood control.
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$response = $this->loginRequest($incorrect_user1->getUsername(), $incorrect_user1->passRaw);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Sorry, unrecognized username or password.');
|
||||
}
|
||||
|
||||
// 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.
|
||||
$response = $this->loginRequest($user1->getUsername(), $user1->passRaw);
|
||||
// Depending on the uid_only setting the error message will be different.
|
||||
if ($uid_only_setting) {
|
||||
$excepted_message = 'There have been more than 3 failed login attempts for this account. It is temporarily blocked. Try again later or request a new password.';
|
||||
}
|
||||
else {
|
||||
$excepted_message = 'Too many failed login attempts from your IP address. This IP address is temporarily blocked.';
|
||||
}
|
||||
$this->assertHttpResponseWithMessage($response, 403, $excepted_message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a logout HTTP request.
|
||||
*
|
||||
* @param string $format
|
||||
* The format to use to make the request.
|
||||
* @param string $logout_token
|
||||
* The csrf token for user logout.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface The HTTP response.
|
||||
* The HTTP response.
|
||||
*/
|
||||
protected function logoutRequest($format = 'json', $logout_token = '') {
|
||||
/** @var \GuzzleHttp\Client $client */
|
||||
$client = $this->container->get('http_client');
|
||||
$user_logout_url = Url::fromRoute('user.logout.http')
|
||||
->setRouteParameter('_format', $format)
|
||||
->setAbsolute();
|
||||
if ($logout_token) {
|
||||
$user_logout_url->setOption('query', ['token' => $logout_token]);
|
||||
}
|
||||
$post_options = [
|
||||
'headers' => [
|
||||
'Accept' => "application/$format",
|
||||
],
|
||||
'http_errors' => FALSE,
|
||||
'cookies' => $this->cookies,
|
||||
];
|
||||
|
||||
$response = $client->post($user_logout_url->toString(), $post_options);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test csrf protection of User Logout route.
|
||||
*/
|
||||
public function testLogoutCsrfProtection() {
|
||||
$client = \Drupal::httpClient();
|
||||
$login_status_url = $this->getLoginStatusUrlString();
|
||||
$account = $this->drupalCreateUser();
|
||||
$name = $account->getUsername();
|
||||
$pass = $account->passRaw;
|
||||
|
||||
$response = $this->loginRequest($name, $pass);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$result_data = $this->serializer->decode($response->getBody(), 'json');
|
||||
|
||||
$logout_token = $result_data['logout_token'];
|
||||
|
||||
// Test third party site posting to current site with logout request.
|
||||
// This should not logout the current user because it lacks the CSRF
|
||||
// token.
|
||||
$response = $this->logoutRequest('json');
|
||||
$this->assertEquals(403, $response->getStatusCode());
|
||||
|
||||
// Ensure still logged in.
|
||||
$response = $client->get($login_status_url, ['cookies' => $this->cookies]);
|
||||
$this->assertHttpResponse($response, 200, UserAuthenticationController::LOGGED_IN);
|
||||
|
||||
// Try with an incorrect token.
|
||||
$response = $this->logoutRequest('json', 'not-the-correct-token');
|
||||
$this->assertEquals(403, $response->getStatusCode());
|
||||
|
||||
// Ensure still logged in.
|
||||
$response = $client->get($login_status_url, ['cookies' => $this->cookies]);
|
||||
$this->assertHttpResponse($response, 200, UserAuthenticationController::LOGGED_IN);
|
||||
|
||||
// Try a logout request with correct token.
|
||||
$response = $this->logoutRequest('json', $logout_token);
|
||||
$this->assertEquals(204, $response->getStatusCode());
|
||||
|
||||
// Ensure actually logged out.
|
||||
$response = $client->get($login_status_url, ['cookies' => $this->cookies]);
|
||||
$this->assertHttpResponse($response, 200, UserAuthenticationController::LOGGED_OUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL string for checking login.
|
||||
*
|
||||
* @param string $format
|
||||
* The format to use to make the request.
|
||||
*
|
||||
* @return string
|
||||
* The URL string.
|
||||
*/
|
||||
protected function getLoginStatusUrlString($format = 'json') {
|
||||
$user_login_status_url = Url::fromRoute('user.login_status.http');
|
||||
$user_login_status_url->setRouteParameter('_format', $format);
|
||||
$user_login_status_url->setAbsolute();
|
||||
return $user_login_status_url->toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\Tests\user\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\Tests\file\Kernel\Migrate\d6\FileMigrationTestTrait;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
||||
|
||||
/**
|
||||
|
@ -12,6 +13,8 @@ use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
|||
*/
|
||||
class MigrateUserPictureFileTest extends MigrateDrupal6TestBase {
|
||||
|
||||
use FileMigrationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -19,13 +22,7 @@ class MigrateUserPictureFileTest extends MigrateDrupal6TestBase {
|
|||
parent::setUp();
|
||||
|
||||
$this->installEntitySchema('file');
|
||||
|
||||
/** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
|
||||
$migration = $this->getMigration('d6_user_picture_file');
|
||||
$source = $migration->getSourceConfiguration();
|
||||
$source['site_path'] = 'core/modules/simpletest';
|
||||
$migration->set('source', $source);
|
||||
$this->executeMigration($migration);
|
||||
$this->executeMigration('d6_user_picture_file');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\Tests\user\Kernel\Migrate\d6;
|
||||
|
||||
use Drupal\migrate\MigrateExecutable;
|
||||
use Drupal\Tests\file\Kernel\Migrate\d6\FileMigrationTestTrait;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\Core\Database\Database;
|
||||
|
@ -16,6 +17,8 @@ use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
|
|||
*/
|
||||
class MigrateUserTest extends MigrateDrupal6TestBase {
|
||||
|
||||
use FileMigrationTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -29,7 +29,7 @@ class MigrateUserRoleTest extends MigrateDrupal7TestBase {
|
|||
* The role ID.
|
||||
* @param string $label
|
||||
* The role's expected label.
|
||||
* @param int|NULL $original_rid
|
||||
* @param int|null $original_rid
|
||||
* The original (integer) ID of the role, to check permissions.
|
||||
*/
|
||||
protected function assertEntity($id, $label, $original_rid) {
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
namespace Drupal\Tests\user\Kernel\Migrate\d7;
|
||||
|
||||
use Drupal\comment\Entity\CommentType;
|
||||
use Drupal\node\Entity\NodeType;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
@ -17,7 +20,18 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['file', 'image'];
|
||||
public static $modules = [
|
||||
'comment',
|
||||
'datetime',
|
||||
'file',
|
||||
'image',
|
||||
'link',
|
||||
'node',
|
||||
'system',
|
||||
'taxonomy',
|
||||
'telephone',
|
||||
'text',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
|
@ -27,14 +41,42 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
|||
|
||||
// Prepare to migrate user pictures as well.
|
||||
$this->installEntitySchema('file');
|
||||
$this->createType('page');
|
||||
$this->createType('article');
|
||||
$this->createType('blog');
|
||||
$this->createType('book');
|
||||
$this->createType('forum');
|
||||
$this->createType('test_content_type');
|
||||
Vocabulary::create(['vid' => 'test_vocabulary'])->save();
|
||||
$this->executeMigrations([
|
||||
'user_picture_field',
|
||||
'user_picture_field_instance',
|
||||
'd7_user_role',
|
||||
'd7_field',
|
||||
'd7_field_instance',
|
||||
'd7_user',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a node type with a corresponding comment type.
|
||||
*
|
||||
* @param string $id
|
||||
* The node type ID.
|
||||
*/
|
||||
protected function createType($id) {
|
||||
NodeType::create([
|
||||
'type' => $id,
|
||||
'label' => $this->randomString(),
|
||||
])->save();
|
||||
|
||||
CommentType::create([
|
||||
'id' => 'comment_node_' . $id,
|
||||
'label' => $this->randomString(),
|
||||
'target_entity_type_id' => 'node',
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts various aspects of a user account.
|
||||
*
|
||||
|
@ -60,8 +102,10 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
|||
* Role IDs the user account is expected to have.
|
||||
* @param bool $has_picture
|
||||
* Whether the user is expected to have a picture attached.
|
||||
* @param int $field_integer
|
||||
* The value of the integer field.
|
||||
*/
|
||||
protected function assertEntity($id, $label, $mail, $password, $access, $login, $blocked, $langcode, $init, array $roles = [RoleInterface::AUTHENTICATED_ID], $has_picture = FALSE) {
|
||||
protected function assertEntity($id, $label, $mail, $password, $access, $login, $blocked, $langcode, $init, array $roles = [RoleInterface::AUTHENTICATED_ID], $has_picture = FALSE, $field_integer = NULL) {
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = User::load($id);
|
||||
$this->assertTrue($user instanceof UserInterface);
|
||||
|
@ -80,6 +124,10 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
|||
$this->assertIdentical($roles, $user->getRoles());
|
||||
$this->assertIdentical($has_picture, !$user->user_picture->isEmpty());
|
||||
$this->assertIdentical($password, $user->getPassword());
|
||||
if (!is_null($field_integer)) {
|
||||
$this->assertTrue($user->hasField('field_integer'));
|
||||
$this->assertEquals($field_integer, $user->field_integer->value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,7 +135,7 @@ class MigrateUserTest extends MigrateDrupal7TestBase {
|
|||
*/
|
||||
public function testUser() {
|
||||
$password = '$S$DGFZUE.FhrXbe4y52eC7p0ZVRGD/gOPtVctDlmC89qkujnBokAlJ';
|
||||
$this->assertEntity(2, 'Odo', 'odo@local.host', $password, '0', '0', FALSE, '', 'odo@local.host');
|
||||
$this->assertEntity(2, 'Odo', 'odo@local.host', $password, '0', '0', FALSE, 'en', 'odo@local.host', [RoleInterface::AUTHENTICATED_ID], FALSE, 99);
|
||||
|
||||
// Ensure that the user can authenticate.
|
||||
$this->assertEquals(2, \Drupal::service('user.auth')->authenticate('Odo', 'a password'));
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Kernel\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Kernel\MigrateSqlSourceTestBase;
|
||||
|
||||
/**
|
||||
* Tests the d7_user_role source plugin.
|
||||
*
|
||||
* @covers \Drupal\user\Plugin\migrate\source\d7\Role
|
||||
* @group user
|
||||
*/
|
||||
class RoleTest extends MigrateSqlSourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['migrate_drupal', 'user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function providerSource() {
|
||||
$expected = [
|
||||
[
|
||||
'rid' => 1,
|
||||
'name' => 'anonymous user',
|
||||
'permissions' => [
|
||||
'access content',
|
||||
],
|
||||
],
|
||||
[
|
||||
'rid' => 2,
|
||||
'name' => 'authenticated user',
|
||||
'permissions' => [
|
||||
'access comments',
|
||||
'access content',
|
||||
'post comments',
|
||||
'post comments without approval',
|
||||
],
|
||||
],
|
||||
[
|
||||
'rid' => 3,
|
||||
'name' => 'administrator',
|
||||
'permissions' => [
|
||||
'access comments',
|
||||
'administer comments',
|
||||
'post comments',
|
||||
'post comments without approval',
|
||||
'access content',
|
||||
'administer content types',
|
||||
'administer nodes',
|
||||
],
|
||||
],
|
||||
];
|
||||
$data = [
|
||||
[[], $expected],
|
||||
];
|
||||
foreach ($expected as $row) {
|
||||
foreach ($row['permissions'] as $permission) {
|
||||
$data[0][0]['role_permission'][] = [
|
||||
'permission' => $permission,
|
||||
'rid' => $row['rid'],
|
||||
];
|
||||
}
|
||||
unset($row['permissions']);
|
||||
$data[0][0]['role'][] = $row;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
|
@ -135,7 +135,7 @@ class UserAccountFormFieldsTest extends KernelTestBase {
|
|||
$entity = $this->container->get('entity.manager')
|
||||
->getStorage($entity_type)
|
||||
->create($fields);
|
||||
$form_object = $this->container->get('entity.manager')
|
||||
$this->container->get('entity.manager')
|
||||
->getFormObject($entity_type, $operation)
|
||||
->setEntity($entity);
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ class UserValidationTest extends KernelTestBase {
|
|||
'foo@example.com' => array('Valid username', 'assertNull'),
|
||||
'foo@-example.com' => array('Valid username', 'assertNull'), // invalid domains are allowed in usernames
|
||||
'þòøÇߪř€' => array('Valid username', 'assertNull'),
|
||||
'foo+bar' => array('Valid username', 'assertNull'), // '+' symbol is allowed
|
||||
'ᚠᛇᚻ᛫ᛒᛦᚦ' => array('Valid UTF8 username', 'assertNull'), // runes
|
||||
' foo' => array('Invalid username that starts with a space', 'assertNotNull'),
|
||||
'foo ' => array('Invalid username that ends with a space', 'assertNotNull'),
|
||||
|
|
|
@ -105,25 +105,25 @@ class PermissionHandlerTest extends UnitTestCase {
|
|||
|
||||
$url = vfsStream::url('modules');
|
||||
mkdir($url . '/module_a');
|
||||
file_put_contents($url . '/module_a/module_a.permissions.yml',
|
||||
"access_module_a: single_description"
|
||||
);
|
||||
file_put_contents($url . '/module_a/module_a.permissions.yml', "access_module_a: single_description");
|
||||
mkdir($url . '/module_b');
|
||||
file_put_contents($url . '/module_b/module_b.permissions.yml',
|
||||
"'access module b':
|
||||
file_put_contents($url . '/module_b/module_b.permissions.yml', <<<EOF
|
||||
'access module b':
|
||||
title: 'Access B'
|
||||
description: 'bla bla'
|
||||
'access module a via module b':
|
||||
title: 'Access A via B'
|
||||
provider: 'module_a'
|
||||
");
|
||||
EOF
|
||||
);
|
||||
mkdir($url . '/module_c');
|
||||
file_put_contents($url . '/module_c/module_c.permissions.yml',
|
||||
"'access_module_c':
|
||||
file_put_contents($url . '/module_c/module_c.permissions.yml', <<<EOF
|
||||
'access_module_c':
|
||||
title: 'Access C'
|
||||
description: 'bla bla'
|
||||
'restrict access': TRUE
|
||||
");
|
||||
EOF
|
||||
);
|
||||
$modules = array('module_a', 'module_b', 'module_c');
|
||||
$extensions = array(
|
||||
'module_a' => $this->mockModuleExtension('module_a', 'Module a'),
|
||||
|
@ -187,9 +187,10 @@ class PermissionHandlerTest extends UnitTestCase {
|
|||
|
||||
$url = vfsStream::url('modules');
|
||||
mkdir($url . '/module_a');
|
||||
file_put_contents($url . '/module_a/module_a.permissions.yml',
|
||||
"access_module_a2: single_description2
|
||||
access_module_a1: single_description1"
|
||||
file_put_contents($url . '/module_a/module_a.permissions.yml', <<<EOF
|
||||
access_module_a2: single_description2
|
||||
access_module_a1: single_description1
|
||||
EOF
|
||||
);
|
||||
mkdir($url . '/module_b');
|
||||
file_put_contents($url . '/module_b/module_b.permissions.yml',
|
||||
|
@ -234,21 +235,24 @@ access_module_a1: single_description1"
|
|||
|
||||
$url = vfsStream::url('modules');
|
||||
mkdir($url . '/module_a');
|
||||
file_put_contents($url . '/module_a/module_a.permissions.yml',
|
||||
"permission_callbacks:
|
||||
file_put_contents($url . '/module_a/module_a.permissions.yml', <<<EOF
|
||||
permission_callbacks:
|
||||
- 'Drupal\\user\\Tests\\TestPermissionCallbacks::singleDescription'
|
||||
");
|
||||
EOF
|
||||
);
|
||||
mkdir($url . '/module_b');
|
||||
file_put_contents($url . '/module_b/module_b.permissions.yml',
|
||||
"permission_callbacks:
|
||||
file_put_contents($url . '/module_b/module_b.permissions.yml', <<<EOF
|
||||
permission_callbacks:
|
||||
- 'Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescription'
|
||||
- 'Drupal\\user\\Tests\\TestPermissionCallbacks::titleProvider'
|
||||
");
|
||||
EOF
|
||||
);
|
||||
mkdir($url . '/module_c');
|
||||
file_put_contents($url . '/module_c/module_c.permissions.yml',
|
||||
"permission_callbacks:
|
||||
file_put_contents($url . '/module_c/module_c.permissions.yml', <<<EOF
|
||||
permission_callbacks:
|
||||
- 'Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescriptionRestrictAccess'
|
||||
");
|
||||
EOF
|
||||
);
|
||||
|
||||
$modules = array('module_a', 'module_b', 'module_c');
|
||||
$extensions = array(
|
||||
|
@ -309,13 +313,14 @@ access_module_a1: single_description1"
|
|||
|
||||
$url = vfsStream::url('modules');
|
||||
mkdir($url . '/module_a');
|
||||
file_put_contents($url . '/module_a/module_a.permissions.yml',
|
||||
"'access module a':
|
||||
file_put_contents($url . '/module_a/module_a.permissions.yml', <<<EOF
|
||||
'access module a':
|
||||
title: 'Access A'
|
||||
description: 'bla bla'
|
||||
permission_callbacks:
|
||||
- 'Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescription'
|
||||
");
|
||||
EOF
|
||||
);
|
||||
|
||||
$modules = array('module_a');
|
||||
$extensions = array(
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Drupal\Tests\user\Unit\Plugin\Core\Entity;
|
|||
use Drupal\Tests\Core\Session\UserSessionTest;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\user\Entity\User
|
||||
* @group user
|
||||
*/
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Unit\Plugin\migrate\source\d7;
|
||||
|
||||
use Drupal\Tests\migrate\Unit\MigrateSqlSourceTestCase;
|
||||
|
||||
/**
|
||||
* Tests D7 role source plugin.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class RoleTest extends MigrateSqlSourceTestCase {
|
||||
|
||||
const PLUGIN_CLASS = 'Drupal\user\Plugin\migrate\source\d7\Role';
|
||||
|
||||
protected $migrationConfiguration = array(
|
||||
'id' => 'test',
|
||||
'source' => array(
|
||||
'plugin' => 'd7_user_role',
|
||||
),
|
||||
);
|
||||
|
||||
protected $expectedResults = array(
|
||||
array(
|
||||
'rid' => 1,
|
||||
'name' => 'anonymous user',
|
||||
'permissions' => array(
|
||||
'access content',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'rid' => 2,
|
||||
'name' => 'authenticated user',
|
||||
'permissions' => array(
|
||||
'access comments',
|
||||
'access content',
|
||||
'post comments',
|
||||
'post comments without approval',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'rid' => 3,
|
||||
'name' => 'administrator',
|
||||
'permissions' => array(
|
||||
'access comments',
|
||||
'administer comments',
|
||||
'post comments',
|
||||
'post comments without approval',
|
||||
'access content',
|
||||
'administer content types',
|
||||
'administer nodes',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
foreach ($this->expectedResults as $row) {
|
||||
foreach ($row['permissions'] as $permission) {
|
||||
$this->databaseContents['role_permission'][] = array(
|
||||
'permission' => $permission,
|
||||
'rid' => $row['rid'],
|
||||
);
|
||||
}
|
||||
unset($row['permissions']);
|
||||
$this->databaseContents['role'][] = $row;
|
||||
}
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
}
|
|
@ -232,7 +232,8 @@ function user_load($uid, $reset = FALSE) {
|
|||
* @see \Drupal\user\Entity\User::loadMultiple()
|
||||
*/
|
||||
function user_load_by_mail($mail) {
|
||||
$users = entity_load_multiple_by_properties('user', array('mail' => $mail));
|
||||
$users = \Drupal::entityTypeManager()->getStorage('user')
|
||||
->loadByProperties(['mail' => $mail]);
|
||||
return $users ? reset($users) : FALSE;
|
||||
}
|
||||
|
||||
|
@ -248,7 +249,8 @@ function user_load_by_mail($mail) {
|
|||
* @see \Drupal\user\Entity\User::loadMultiple()
|
||||
*/
|
||||
function user_load_by_name($name) {
|
||||
$users = entity_load_multiple_by_properties('user', array('name' => $name));
|
||||
$users = \Drupal::entityTypeManager()->getStorage('user')
|
||||
->loadByProperties(['name' => $name]);
|
||||
return $users ? reset($users) : FALSE;
|
||||
}
|
||||
|
||||
|
@ -984,7 +986,7 @@ function user_user_role_insert(RoleInterface $role) {
|
|||
}
|
||||
|
||||
$add_id = 'user_add_role_action.' . $role->id();
|
||||
if (!entity_load('action', $add_id)) {
|
||||
if (!Action::load($add_id)) {
|
||||
$action = Action::create(array(
|
||||
'id' => $add_id,
|
||||
'type' => 'user',
|
||||
|
@ -997,7 +999,7 @@ function user_user_role_insert(RoleInterface $role) {
|
|||
$action->trustData()->save();
|
||||
}
|
||||
$remove_id = 'user_remove_role_action.' . $role->id();
|
||||
if (!entity_load('action', $remove_id)) {
|
||||
if (!Action::load($remove_id)) {
|
||||
$action = Action::create(array(
|
||||
'id' => $remove_id,
|
||||
'type' => 'user',
|
||||
|
@ -1024,10 +1026,10 @@ function user_user_role_delete(RoleInterface $role) {
|
|||
return;
|
||||
}
|
||||
|
||||
$actions = entity_load_multiple('action', array(
|
||||
$actions = Action::loadMultiple([
|
||||
'user_add_role_action.' . $role->id(),
|
||||
'user_remove_role_action.' . $role->id(),
|
||||
));
|
||||
]);
|
||||
foreach ($actions as $action) {
|
||||
$action->delete();
|
||||
}
|
||||
|
@ -1247,7 +1249,7 @@ function user_form_process_password_confirm($element) {
|
|||
$password_settings['showStrengthIndicator'] = TRUE;
|
||||
$password_settings += array(
|
||||
'strengthTitle' => t('Password strength:'),
|
||||
'hasWeaknesses' => t('To make your password stronger:'),
|
||||
'hasWeaknesses' => t('Recommendations to make your password stronger:'),
|
||||
'tooShort' => t('Make it at least 12 characters'),
|
||||
'addLowerCase' => t('Add lowercase letters'),
|
||||
'addUpperCase' => t('Add uppercase letters'),
|
||||
|
@ -1332,7 +1334,7 @@ function user_toolbar() {
|
|||
$links_cache_contexts[] = 'user';
|
||||
}
|
||||
else {
|
||||
$links = array(
|
||||
$links = array(
|
||||
'login' => array(
|
||||
'title' => t('Log in'),
|
||||
'url' => Url::fromRoute('user.page'),
|
||||
|
|
|
@ -129,6 +129,34 @@ user.login:
|
|||
options:
|
||||
_maintenance_access: TRUE
|
||||
|
||||
user.login.http:
|
||||
path: '/user/login'
|
||||
defaults:
|
||||
_controller: \Drupal\user\Controller\UserAuthenticationController::login
|
||||
methods: [POST]
|
||||
requirements:
|
||||
_user_is_logged_in: 'FALSE'
|
||||
_format: 'json'
|
||||
|
||||
user.login_status.http:
|
||||
path: '/user/login_status'
|
||||
defaults:
|
||||
_controller: \Drupal\user\Controller\UserAuthenticationController::loginStatus
|
||||
methods: [GET]
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
_format: 'json'
|
||||
|
||||
user.logout.http:
|
||||
path: '/user/logout'
|
||||
defaults:
|
||||
_controller: \Drupal\user\Controller\UserAuthenticationController::logout
|
||||
methods: [POST]
|
||||
requirements:
|
||||
_user_is_logged_in: 'TRUE'
|
||||
_format: 'json'
|
||||
_csrf_token: 'TRUE'
|
||||
|
||||
user.cancel_confirm:
|
||||
path: '/user/{user}/cancel/confirm/{timestamp}/{hashed_pass}'
|
||||
defaults:
|
||||
|
|
Reference in a new issue