Move all files to 2017/
This commit is contained in:
parent
ac7370f67f
commit
2875863330
15717 changed files with 0 additions and 0 deletions
22
2017/web/core/modules/user/tests/fixtures/update/drupal-8.user-email-token-2587275.php
vendored
Normal file
22
2017/web/core/modules/user/tests/fixtures/update/drupal-8.user-email-token-2587275.php
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains database additions to drupal-8.bare.standard.php.gz for testing the
|
||||
* upgrade path of https://www.drupal.org/node/2587275.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
|
||||
$connection = Database::getConnection();
|
||||
|
||||
// Replace the user.mail configuration because the dump contains the right token
|
||||
// already.
|
||||
$connection->delete('config')->condition('name', 'user.mail')->execute();
|
||||
$connection->insert('config')
|
||||
->fields(['collection', 'name', 'data'])
|
||||
->values([
|
||||
'collection' => '',
|
||||
'name' => 'user.mail',
|
||||
'data' => "a:10:{s:14:\"cancel_confirm\";a:2:{s:4:\"body\";s:369:\"[user:name],\n\nA request to cancel your account has been made at [site:name].\n\nYou may now cancel your account on [site:url-brief] by clicking this link or copying and pasting it into your browser:\n\n[user:cancel-url]\n\nNOTE: The cancellation of your account is not reversible.\n\nThis link expires in one day and nothing will happen if it is not used.\n\n-- [site:name] team\";s:7:\"subject\";s:59:\"Account cancellation request for [user:name] at [site:name]\";}s:14:\"password_reset\";a:2:{s:4:\"body\";s:397:\"[user:name],\n\nA request to reset the password for your account has been made at [site:name].\n\nYou may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password. It expires after one day and nothing will happen if it's not used.\n\n-- [site:name] team\";s:7:\"subject\";s:60:\"Replacement login information for [user:name] at [site:name]\";}s:22:\"register_admin_created\";a:2:{s:4:\"body\";s:463:\"[user:name],\n\nA site administrator at [site:name] has created an account for you. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team\";s:7:\"subject\";s:58:\"An administrator created an account for you at [site:name]\";}s:29:\"register_no_approval_required\";a:2:{s:4:\"body\";s:437:\"[user:name],\n\nThank you for registering at [site:name]. You may now log in by clicking this link or copying and pasting it to your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team\";s:7:\"subject\";s:46:\"Account details for [user:name] at [site:name]\";}s:25:\"register_pending_approval\";a:2:{s:4:\"body\";s:281:\"[user:name],\n\nThank you for registering at [site:name]. Your application for an account is currently pending approval. Once it has been approved, you will receive another email containing information about how to log in, set your password, and other details.\n\n\n-- [site:name] team\";s:7:\"subject\";s:71:\"Account details for [user:name] at [site:name] (pending admin approval)\";}s:31:\"register_pending_approval_admin\";a:2:{s:4:\"body\";s:56:\"[user:name] has applied for an account.\n\n[user:edit-url]\";s:7:\"subject\";s:71:\"Account details for [user:name] at [site:name] (pending admin approval)\";}s:16:\"status_activated\";a:2:{s:4:\"body\";s:446:\"[user:name],\n\nYour account at [site:name] has been activated.\n\nYou may now log in by clicking this link or copying and pasting it into your browser:\n\n[user:one-time-login-url]\n\nThis link can only be used once to log in and will lead you to a page where you can set your password.\n\nAfter setting your password, you will be able to log in at [site:login-url] in the future using:\n\nusername: [user:name]\npassword: Your password\n\n-- [site:name] team\";s:7:\"subject\";s:57:\"Account details for [user:name] at [site:name] (approved)\";}s:14:\"status_blocked\";a:2:{s:4:\"body\";s:89:\"[user:name],\n\nYour account on [site:account-name] has been blocked.\n\n-- [site:name] team\";s:7:\"subject\";s:56:\"Account details for [user:name] at [site:name] (blocked)\";}s:15:\"status_canceled\";a:2:{s:4:\"body\";s:82:\"[user:name],\n\nYour account on [site:name] has been canceled.\n\n-- [site:name] team\";s:7:\"subject\";s:57:\"Account details for [user:name] at [site:name] (canceled)\";}s:8:\"langcode\";s:2:\"en\";}",
|
||||
])->execute();
|
|
@ -0,0 +1,6 @@
|
|||
name: 'User access tests'
|
||||
type: module
|
||||
description: 'Support module for user access testing.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Dummy module implementing hook_user_access() to test if entity access is respected.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Implements hook_ENTITY_TYPE_access() for entity type "user".
|
||||
*/
|
||||
function user_access_test_user_access(User $entity, $operation, $account) {
|
||||
if ($entity->getUsername() == "no_edit" && $operation == "update") {
|
||||
// Deny edit access.
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
if ($entity->getUsername() == "no_delete" && $operation == "delete") {
|
||||
// Deny delete access.
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_field_access().
|
||||
*/
|
||||
function user_access_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
|
||||
// Account with role sub-admin can view the status, init and mail fields for user with no roles.
|
||||
if ($operation === 'view' && in_array($field_definition->getName(), ['status', 'init', 'mail'])) {
|
||||
if (($items == NULL) || (count($items->getEntity()->getRoles()) == 1)) {
|
||||
return AccessResult::allowedIfHasPermission($account, 'sub-admin');
|
||||
}
|
||||
}
|
||||
return AccessResult::neutral();
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
sub-admin:
|
||||
title: 'Administer users with no roles'
|
|
@ -0,0 +1,6 @@
|
|||
name: 'User custom phpass params test'
|
||||
type: module
|
||||
description: 'Support module for testing custom phpass password algorithm parameters.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,4 @@
|
|||
services:
|
||||
password:
|
||||
class: Drupal\Core\Password\PhpassHashedPassword
|
||||
arguments: [19]
|
|
@ -0,0 +1,6 @@
|
|||
name: 'User module form tests'
|
||||
type: module
|
||||
description: 'Support module for user form testing.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Support module for user form testing.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter() for user_cancel_form().
|
||||
*/
|
||||
function user_form_test_form_user_cancel_form_alter(&$form, &$form_state) {
|
||||
$form['user_cancel_confirm']['#default_value'] = FALSE;
|
||||
$form['access']['#value'] = \Drupal::currentUser()->hasPermission('cancel other accounts');
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
cancel other accounts:
|
||||
title: 'Cancel other user accounts'
|
|
@ -0,0 +1,6 @@
|
|||
user_form_test.cancel:
|
||||
path: '/user_form_test_cancel/{user}'
|
||||
defaults:
|
||||
_entity_form: 'user.cancel'
|
||||
requirements:
|
||||
_permission: 'cancel other accounts'
|
|
@ -0,0 +1,6 @@
|
|||
name: 'User module hooks tests'
|
||||
type: module
|
||||
description: 'Support module for user hooks testing.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Support module for user hooks testing.
|
||||
*/
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Implements hook_user_format_name_alter().
|
||||
*/
|
||||
function user_hooks_test_user_format_name_alter(&$name, AccountInterface $account) {
|
||||
if (\Drupal::state()->get('user_hooks_test_user_format_name_alter', FALSE)) {
|
||||
if (\Drupal::state()->get('user_hooks_test_user_format_name_alter_safe', FALSE)) {
|
||||
$name = new FormattableMarkup('<em>@uid</em>', ['@uid' => $account->id()]);
|
||||
}
|
||||
else {
|
||||
$name = '<em>' . $account->id() . '</em>';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_access_perm
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'views_test_data test permission'
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -0,0 +1,45 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_access_role
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: views_test_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
fields:
|
||||
id:
|
||||
id: id
|
||||
field: id
|
||||
table: views_test_data
|
||||
plugin_id: numeric
|
||||
access:
|
||||
type: role
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
||||
page_1:
|
||||
display_options:
|
||||
path: test-role
|
||||
display_plugin: page
|
||||
display_title: Page
|
||||
id: page_1
|
||||
position: 1
|
|
@ -0,0 +1,139 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_field_permission
|
||||
label: null
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: null
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
uid:
|
||||
id: uid
|
||||
table: users_field_data
|
||||
field: uid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Uid
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
plugin_id: field
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
permission:
|
||||
id: permission
|
||||
table: user__roles
|
||||
field: permission
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Permission
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
type: separator
|
||||
separator: ', '
|
||||
plugin_id: user_permissions
|
||||
filters: { }
|
||||
sorts: { }
|
|
@ -0,0 +1,119 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_filter_current_user
|
||||
label: Users
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Filter
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: default
|
||||
options:
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
uses_fields: false
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
separator: ''
|
||||
hide_empty: false
|
||||
default_field_elements: true
|
||||
fields:
|
||||
uid:
|
||||
id: uid
|
||||
table: users
|
||||
field: uid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
filters:
|
||||
uid_current:
|
||||
id: uid_current
|
||||
table: users
|
||||
field: uid_current
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: '1'
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
entity_type: user
|
||||
plugin_id: user_current
|
||||
sorts: { }
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: -1
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- user
|
||||
tags: { }
|
|
@ -0,0 +1,142 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_filter_permission
|
||||
label: null
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: null
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
uid:
|
||||
id: uid
|
||||
table: users
|
||||
field: uid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
link_to_user: false
|
||||
plugin_id: user
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
filters:
|
||||
permission:
|
||||
id: permission
|
||||
table: user__roles
|
||||
field: permission
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: or
|
||||
value:
|
||||
'access user profiles': 'access user profiles'
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: '0'
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
reduce: false
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
reduce_duplicates: true
|
||||
plugin_id: user_permissions
|
||||
sorts:
|
||||
uid:
|
||||
id: uid
|
||||
table: users_field_data
|
||||
field: uid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: ASC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
plugin_id: standard
|
||||
entity_type: user
|
||||
entity_field: uid
|
|
@ -0,0 +1,93 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
- user
|
||||
id: test_groupwise_user
|
||||
label: test_groupwise_user
|
||||
module: views
|
||||
description: ''
|
||||
tag: default
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.0-dev
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
options:
|
||||
perm: 'access user profiles'
|
||||
type: perm
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
fields:
|
||||
name:
|
||||
field: name
|
||||
id: name
|
||||
table: users_field_data
|
||||
plugin_id: field
|
||||
type: user_name
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
nid:
|
||||
field: nid
|
||||
id: nid
|
||||
relationship: uid_representative
|
||||
table: node_field_data
|
||||
plugin_id: node
|
||||
entity_type: node
|
||||
entity_field: nid
|
||||
filters:
|
||||
status:
|
||||
expose:
|
||||
operator: '0'
|
||||
field: status
|
||||
group: 1
|
||||
id: status
|
||||
table: users_field_data
|
||||
value: '1'
|
||||
plugin_id: boolean
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
pager:
|
||||
options:
|
||||
items_per_page: 10
|
||||
type: full
|
||||
query:
|
||||
type: views_query
|
||||
relationships:
|
||||
uid_representative:
|
||||
admin_label: 'Representative node'
|
||||
field: uid_representative
|
||||
group_type: group
|
||||
id: uid_representative
|
||||
relationship: none
|
||||
required: false
|
||||
subquery_namespace: ''
|
||||
subquery_order: DESC
|
||||
subquery_regenerate: true
|
||||
subquery_sort: node.nid
|
||||
subquery_view: ''
|
||||
table: users_field_data
|
||||
plugin_id: groupwise_max
|
||||
row:
|
||||
type: fields
|
||||
sorts:
|
||||
created:
|
||||
field: uid
|
||||
id: uid
|
||||
order: ASC
|
||||
table: users_field_data
|
||||
plugin_id: field
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
style:
|
||||
type: default
|
||||
title: test_groupwise_user
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -0,0 +1,63 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
id: test_plugin_argument_default_current_user
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
arguments:
|
||||
'null':
|
||||
default_action: default
|
||||
default_argument_type: current_user
|
||||
field: 'null'
|
||||
id: 'null'
|
||||
must_not_be: false
|
||||
table: views
|
||||
plugin_id: 'null'
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
fields:
|
||||
title:
|
||||
alter:
|
||||
alter_text: false
|
||||
ellipsis: true
|
||||
html: false
|
||||
make_link: false
|
||||
strip_tags: false
|
||||
trim: false
|
||||
word_boundary: true
|
||||
empty_zero: false
|
||||
field: title
|
||||
hide_empty: false
|
||||
id: title
|
||||
table: node_field_data
|
||||
plugin_id: field
|
||||
entity_type: node
|
||||
entity_field: title
|
||||
pager:
|
||||
options:
|
||||
id: 0
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
type: full
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -0,0 +1,65 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_user_bulk_form
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: null
|
||||
display_options:
|
||||
style:
|
||||
type: table
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
user_bulk_form:
|
||||
id: user_bulk_form
|
||||
table: users
|
||||
field: user_bulk_form
|
||||
plugin_id: user_bulk_form
|
||||
entity_type: user
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
plugin_id: field
|
||||
type: user_name
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
sorts:
|
||||
uid:
|
||||
id: uid
|
||||
table: users_field_data
|
||||
field: uid
|
||||
order: ASC
|
||||
plugin_id: user
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
filters:
|
||||
status:
|
||||
id: status
|
||||
table: users_field_data
|
||||
field: status
|
||||
operator: '='
|
||||
value: '1'
|
||||
plugin_id: boolean
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: null
|
||||
display_options:
|
||||
path: test-user-bulk-form
|
|
@ -0,0 +1,243 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_user_bulk_form_combine_filter
|
||||
label: test_user_bulk_form_combine_filter
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
options: { }
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: full
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: null
|
||||
expose:
|
||||
items_per_page: false
|
||||
items_per_page_label: 'Items per page'
|
||||
items_per_page_options: '5, 10, 25, 50'
|
||||
items_per_page_options_all: false
|
||||
items_per_page_options_all_label: '- All -'
|
||||
offset: false
|
||||
offset_label: Offset
|
||||
tags:
|
||||
previous: '‹ Previous'
|
||||
next: 'Next ›'
|
||||
first: '« First'
|
||||
last: 'Last »'
|
||||
quantity: 9
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
user_bulk_form:
|
||||
id: user_bulk_form
|
||||
table: users
|
||||
field: user_bulk_form
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
action_title: 'With selection'
|
||||
include_exclude: exclude
|
||||
selected_actions: { }
|
||||
entity_type: user
|
||||
plugin_id: user_bulk_form
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
plugin_id: field
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: user_name
|
||||
settings: { }
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
filters:
|
||||
combine:
|
||||
id: combine
|
||||
table: views
|
||||
field: combine
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: contains
|
||||
value: dummy
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: ''
|
||||
identifier: ''
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
fields:
|
||||
user_bulk_form: user_bulk_form
|
||||
name: name
|
||||
plugin_id: combine
|
||||
sorts: { }
|
||||
title: test_user_bulk_form_combine_filter
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups:
|
||||
1: AND
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
tags: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: test-user-bulk-form-combine-filter
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
tags: { }
|
|
@ -0,0 +1,60 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_user_changed
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
row:
|
||||
type: fields
|
||||
style:
|
||||
type: default
|
||||
fields:
|
||||
name:
|
||||
id: uid
|
||||
table: users_field_data
|
||||
field: uid
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
changed:
|
||||
id: changed
|
||||
table: users_field_data
|
||||
field: changed
|
||||
label: 'Updated date'
|
||||
plugin_id: field
|
||||
type: timestamp
|
||||
settings:
|
||||
date_format: html_date
|
||||
custom_date_format: ''
|
||||
timezone: ''
|
||||
entity_type: user
|
||||
entity_field: changed
|
||||
filters: { }
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
||||
page_1:
|
||||
display_options:
|
||||
path: test_user_changed
|
||||
display_plugin: page
|
||||
display_title: Page
|
||||
id: page_1
|
||||
position: 0
|
|
@ -0,0 +1,131 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_user_data
|
||||
label: test_user_data
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: null
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access user profiles'
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
plugin_id: field
|
||||
type: user_name
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
data:
|
||||
id: data
|
||||
table: users
|
||||
field: data
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Data
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
data_module: views_test_config
|
||||
data_name: test_value_name
|
||||
plugin_id: user_data
|
||||
entity_type: user
|
||||
filters:
|
||||
uid:
|
||||
value:
|
||||
value: '2'
|
||||
table: users_field_data
|
||||
field: uid
|
||||
id: uid
|
||||
expose:
|
||||
operator: '0'
|
||||
group: 1
|
||||
plugin_id: numeric
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
table: users_field_data
|
||||
field: created
|
||||
order: DESC
|
||||
plugin_id: date
|
||||
entity_type: user
|
||||
entity_field: created
|
|
@ -0,0 +1,478 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_user_fields_access
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
options: { }
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: mini
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: null
|
||||
expose:
|
||||
items_per_page: false
|
||||
items_per_page_label: 'Items per page'
|
||||
items_per_page_options: '5, 10, 25, 50'
|
||||
items_per_page_options_all: false
|
||||
items_per_page_options_all_label: '- All -'
|
||||
offset: false
|
||||
offset_label: Offset
|
||||
tags:
|
||||
previous: ‹‹
|
||||
next: ››
|
||||
style:
|
||||
type: table
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
override: true
|
||||
sticky: false
|
||||
caption: ''
|
||||
summary: ''
|
||||
description: ''
|
||||
columns:
|
||||
name: name
|
||||
status: status
|
||||
mail: mail
|
||||
init: init
|
||||
created: created
|
||||
info:
|
||||
name:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
status:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
mail:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
init:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
created:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
default: '-1'
|
||||
empty_table: false
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Name
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: user_name
|
||||
settings:
|
||||
link_to_entity: true
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
plugin_id: field
|
||||
status:
|
||||
id: status
|
||||
table: users_field_data
|
||||
field: status
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Status
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: boolean
|
||||
settings:
|
||||
format: default
|
||||
format_custom_true: ''
|
||||
format_custom_false: ''
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
plugin_id: field
|
||||
mail:
|
||||
id: mail
|
||||
table: users_field_data
|
||||
field: mail
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Email
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: basic_string
|
||||
settings: { }
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: mail
|
||||
plugin_id: field
|
||||
init:
|
||||
id: init
|
||||
table: users_field_data
|
||||
field: init
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Init
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: basic_string
|
||||
settings: { }
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: init
|
||||
plugin_id: field
|
||||
created:
|
||||
id: created
|
||||
table: users_field_data
|
||||
field: created
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Created
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: timestamp
|
||||
settings:
|
||||
date_format: medium
|
||||
custom_date_format: ''
|
||||
timezone: ''
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
entity_type: user
|
||||
entity_field: created
|
||||
plugin_id: field
|
||||
filters: { }
|
||||
sorts: { }
|
||||
title: ''
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
tags: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: test_user_fields_access
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url.query_args
|
||||
tags: { }
|
|
@ -0,0 +1,62 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_user_name
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
row:
|
||||
type: fields
|
||||
style:
|
||||
type: default
|
||||
fields:
|
||||
name:
|
||||
id: uid
|
||||
table: users_field_data
|
||||
field: uid
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
filters:
|
||||
uid:
|
||||
id: uid
|
||||
table: users_field_data
|
||||
field: uid
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: uid_op
|
||||
label: Name
|
||||
operator: uid_op
|
||||
identifier: uid
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
||||
page_1:
|
||||
display_options:
|
||||
path: test_user_name
|
||||
display_plugin: page
|
||||
display_title: Page
|
||||
id: page_1
|
||||
position: 0
|
|
@ -0,0 +1,115 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
- user
|
||||
id: test_user_relationship
|
||||
label: test_user_relationship
|
||||
module: views
|
||||
description: ''
|
||||
tag: default
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
fields:
|
||||
name:
|
||||
alter:
|
||||
absolute: false
|
||||
alter_text: false
|
||||
ellipsis: true
|
||||
external: false
|
||||
html: false
|
||||
make_link: false
|
||||
nl2br: false
|
||||
replace_spaces: false
|
||||
strip_tags: false
|
||||
trim: false
|
||||
trim_whitespace: false
|
||||
word_boundary: true
|
||||
element_default_classes: true
|
||||
element_label_colon: true
|
||||
empty_zero: false
|
||||
field: name
|
||||
hide_alter_empty: false
|
||||
hide_empty: false
|
||||
id: name
|
||||
table: users_field_data
|
||||
plugin_id: field
|
||||
type: user_name
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
title:
|
||||
alter:
|
||||
absolute: false
|
||||
alter_text: false
|
||||
ellipsis: false
|
||||
html: false
|
||||
make_link: false
|
||||
strip_tags: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
empty_zero: false
|
||||
field: title
|
||||
hide_empty: false
|
||||
id: title
|
||||
label: ''
|
||||
table: node_field_data
|
||||
plugin_id: field
|
||||
entity_type: node
|
||||
entity_field: title
|
||||
uid:
|
||||
alter:
|
||||
absolute: false
|
||||
alter_text: false
|
||||
ellipsis: true
|
||||
external: false
|
||||
html: false
|
||||
make_link: false
|
||||
nl2br: false
|
||||
replace_spaces: false
|
||||
strip_tags: false
|
||||
trim: false
|
||||
trim_whitespace: false
|
||||
word_boundary: true
|
||||
element_default_classes: true
|
||||
element_label_colon: true
|
||||
empty_zero: false
|
||||
field: uid
|
||||
hide_alter_empty: false
|
||||
hide_empty: false
|
||||
id: uid
|
||||
table: users_field_data
|
||||
plugin_id: field
|
||||
type: user
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
pager:
|
||||
options:
|
||||
items_per_page: 10
|
||||
type: full
|
||||
query:
|
||||
options:
|
||||
query_comment: ''
|
||||
type: views_query
|
||||
title: test_user_relationship
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
default_field_elements: true
|
||||
hide_empty: false
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -0,0 +1,220 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_user_roles_rid
|
||||
label: test_user_roles_rid
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: 0
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
options: { }
|
||||
cache:
|
||||
type: tag
|
||||
options: { }
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Apply
|
||||
reset_button: false
|
||||
reset_button_label: Reset
|
||||
exposed_sorts_label: 'Sort by'
|
||||
expose_sort_order: true
|
||||
sort_asc_label: Asc
|
||||
sort_desc_label: Desc
|
||||
pager:
|
||||
type: full
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: null
|
||||
expose:
|
||||
items_per_page: false
|
||||
items_per_page_label: 'Items per page'
|
||||
items_per_page_options: '5, 10, 25, 50'
|
||||
items_per_page_options_all: false
|
||||
items_per_page_options_all_label: '- All -'
|
||||
offset: false
|
||||
offset_label: Offset
|
||||
tags:
|
||||
previous: '‹ Previous'
|
||||
next: 'Next ›'
|
||||
first: '« First'
|
||||
last: 'Last »'
|
||||
quantity: 9
|
||||
style:
|
||||
type: default
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
uses_fields: false
|
||||
row:
|
||||
type: fields
|
||||
options:
|
||||
inline: { }
|
||||
separator: ''
|
||||
hide_empty: false
|
||||
default_field_elements: true
|
||||
fields:
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
label: ''
|
||||
alter:
|
||||
alter_text: false
|
||||
make_link: false
|
||||
absolute: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
ellipsis: false
|
||||
strip_tags: false
|
||||
html: false
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
plugin_id: field
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exclude: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: user_name
|
||||
settings: { }
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: users_field_data
|
||||
field: status
|
||||
plugin_id: boolean
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: ''
|
||||
group: 1
|
||||
sorts:
|
||||
uid:
|
||||
id: uid
|
||||
table: users
|
||||
field: uid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: ASC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
plugin_id: standard
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments:
|
||||
roles_target_id:
|
||||
id: roles_target_id
|
||||
table: user__roles
|
||||
field: roles_target_id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
default_action: empty
|
||||
exception:
|
||||
value: all
|
||||
title_enable: false
|
||||
title: All
|
||||
title_enable: true
|
||||
title: '{{ arguments.roles_target_id }}'
|
||||
default_argument_type: fixed
|
||||
default_argument_options:
|
||||
argument: ''
|
||||
default_argument_skip_url: false
|
||||
summary_options:
|
||||
base_path: ''
|
||||
count: true
|
||||
items_per_page: 25
|
||||
override: false
|
||||
summary:
|
||||
sort_order: asc
|
||||
number_of_records: 0
|
||||
format: default_summary
|
||||
specify_validation: false
|
||||
validate:
|
||||
type: none
|
||||
fail: 'not found'
|
||||
validate_options: { }
|
||||
break_phrase: false
|
||||
add_table: false
|
||||
require_value: false
|
||||
reduce_duplicates: false
|
||||
plugin_id: user__roles_rid
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- url.query_args
|
||||
- user.permissions
|
||||
cacheable: false
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
display_extenders: { }
|
||||
path: user_roles_rid_test
|
||||
cache_metadata:
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- url
|
||||
- url.query_args
|
||||
- user.permissions
|
||||
cacheable: false
|
|
@ -0,0 +1,38 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_user_uid_argument
|
||||
label: null
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
fields:
|
||||
uid:
|
||||
id: uid
|
||||
table: users_field_data
|
||||
field: uid
|
||||
plugin_id: user
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
arguments:
|
||||
uid:
|
||||
id: uid
|
||||
table: users_field_data
|
||||
field: uid
|
||||
title_enable: true
|
||||
title: '{{ arguments.uid }}'
|
||||
plugin_id: user_uid
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -0,0 +1,40 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies: { }
|
||||
id: test_view_argument_validate_user
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
arguments:
|
||||
'null':
|
||||
default_argument_type: fixed
|
||||
field: 'null'
|
||||
id: 'null'
|
||||
must_not_be: false
|
||||
table: views
|
||||
validate:
|
||||
type: 'entity:user'
|
||||
plugin_id: 'null'
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -0,0 +1,40 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies: { }
|
||||
id: test_view_argument_validate_username
|
||||
label: ''
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: node_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
arguments:
|
||||
'null':
|
||||
default_argument_type: fixed
|
||||
field: 'null'
|
||||
id: 'null'
|
||||
must_not_be: false
|
||||
table: views
|
||||
validate:
|
||||
type: user_name
|
||||
plugin_id: 'null'
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: full
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -0,0 +1,177 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_views_handler_field_role
|
||||
label: test_views_handler_field_role
|
||||
module: views
|
||||
description: ''
|
||||
tag: ''
|
||||
base_table: users_field_data
|
||||
base_field: uid
|
||||
core: 8.x
|
||||
display:
|
||||
default:
|
||||
display_plugin: default
|
||||
id: default
|
||||
display_title: Master
|
||||
position: null
|
||||
display_options:
|
||||
access:
|
||||
type: perm
|
||||
options:
|
||||
perm: 'access user profiles'
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
exposed_form:
|
||||
type: basic
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
items_per_page: null
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Name
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
plugin_id: field
|
||||
type: user_name
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
roles_target_id:
|
||||
id: roles_target_id
|
||||
table: user__roles
|
||||
field: roles_target_id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Roles
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
type: separator
|
||||
separator: ''
|
||||
plugin_id: user_roles
|
||||
filters:
|
||||
status:
|
||||
value: '1'
|
||||
table: users_field_data
|
||||
field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: '0'
|
||||
group: 1
|
||||
plugin_id: boolean
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
sorts:
|
||||
uid:
|
||||
id: uid
|
||||
table: users_field_data
|
||||
field: uid
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: ASC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
entity_type: user
|
||||
entity_field: uid
|
||||
plugin_id: standard
|
||||
title: test_user_role
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: null
|
||||
display_options:
|
||||
path: test-views-handler-field-role
|
|
@ -0,0 +1,63 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: test_views_handler_field_user_name
|
||||
label: test_views_handler_field_user_name
|
||||
module: views
|
||||
description: ''
|
||||
tag: default
|
||||
base_table: users_field_data
|
||||
base_field: nid
|
||||
core: '8'
|
||||
display:
|
||||
default:
|
||||
display_options:
|
||||
access:
|
||||
type: none
|
||||
cache:
|
||||
type: tag
|
||||
exposed_form:
|
||||
type: basic
|
||||
fields:
|
||||
name:
|
||||
alter:
|
||||
absolute: false
|
||||
alter_text: false
|
||||
ellipsis: false
|
||||
html: false
|
||||
make_link: false
|
||||
strip_tags: false
|
||||
trim: false
|
||||
word_boundary: false
|
||||
empty_zero: false
|
||||
field: name
|
||||
hide_empty: false
|
||||
id: name
|
||||
label: ''
|
||||
table: users_field_data
|
||||
plugin_id: field
|
||||
type: user_name
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
pager:
|
||||
type: full
|
||||
query:
|
||||
options:
|
||||
query_comment: ''
|
||||
type: views_query
|
||||
style:
|
||||
type: default
|
||||
row:
|
||||
type: fields
|
||||
sorts:
|
||||
uid:
|
||||
id: uid
|
||||
table: users
|
||||
field: uid
|
||||
plugin_id: standard
|
||||
display_plugin: default
|
||||
display_title: Master
|
||||
id: default
|
||||
position: 0
|
|
@ -0,0 +1,9 @@
|
|||
name: 'User test views'
|
||||
type: module
|
||||
description: 'Provides default views for views user tests.'
|
||||
package: Testing
|
||||
version: VERSION
|
||||
core: 8.x
|
||||
dependencies:
|
||||
- drupal:user
|
||||
- drupal:views
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\views_ui\Functional\UITestBase;
|
||||
use Drupal\views\Tests\ViewTestData;
|
||||
|
||||
/**
|
||||
* Tests views role access plugin UI.
|
||||
*
|
||||
* @group user
|
||||
* @see \Drupal\user\Plugin\views\access\Role
|
||||
*/
|
||||
class AccessRoleUITest extends UITestBase {
|
||||
|
||||
/**
|
||||
* Views used by this test.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $testViews = ['test_access_role'];
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['user', 'user_test_views'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
ViewTestData::createTestViews(get_class($this), ['user_test_views']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the role access plugin UI.
|
||||
*/
|
||||
public function testAccessRoleUI() {
|
||||
$entity_manager = $this->container->get('entity.manager');
|
||||
$entity_manager->getStorage('user_role')->create(['id' => 'custom_role', 'label' => 'Custom role'])->save();
|
||||
$access_url = "admin/structure/views/nojs/display/test_access_role/default/access_options";
|
||||
$this->drupalPostForm($access_url, ['access_options[role][custom_role]' => 1], t('Apply'));
|
||||
$this->assertResponse(200);
|
||||
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
$view = $entity_manager->getStorage('view')->load('test_access_role');
|
||||
|
||||
$display = $view->getDisplay('default');
|
||||
$this->assertEqual($display['display_options']['access']['options']['role'], ['custom_role' => 'custom_role']);
|
||||
|
||||
// Test changing access plugin from role to none.
|
||||
$this->drupalPostForm('admin/structure/views/nojs/display/test_access_role/default/access', ['access[type]' => 'none'], t('Apply'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
// Verify that role option is not set.
|
||||
$view = $entity_manager->getStorage('view')->load('test_access_role');
|
||||
$display = $view->getDisplay('default');
|
||||
$this->assertFalse(isset($display['display_options']['access']['options']['role']));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\user\Functional\Rest\RoleResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class RoleHalJsonAnonTest extends RoleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\user\Functional\Rest\RoleResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class RoleHalJsonBasicAuthTest extends RoleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal', 'basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\user\Functional\Rest\RoleResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class RoleHalJsonCookieTest extends RoleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\user\Functional\Rest\UserResourceTestBase;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class UserHalJsonAnonTest extends UserResourceTestBase {
|
||||
|
||||
use HalEntityNormalizationTrait;
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
$default_normalization = parent::getExpectedNormalizedEntity();
|
||||
|
||||
$normalization = $this->applyHalFieldNormalization($default_normalization);
|
||||
|
||||
return $normalization + [
|
||||
'_links' => [
|
||||
'self' => [
|
||||
'href' => $this->baseUrl . '/user/3?_format=hal_json',
|
||||
],
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return parent::getNormalizedPostEntity() + [
|
||||
'_links' => [
|
||||
'type' => [
|
||||
'href' => $this->baseUrl . '/rest/type/user/user',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class UserHalJsonBasicAuthTest extends UserHalJsonAnonTest {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Hal;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group hal
|
||||
*/
|
||||
class UserHalJsonCookieTest extends UserHalJsonAnonTest {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleJsonAnonTest extends RoleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleJsonBasicAuthTest extends RoleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleJsonCookieTest extends RoleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
|
||||
abstract class RoleResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'user_role';
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\RoleInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
$this->grantPermissionsToTestedRole(['administer permissions']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
$role = Role::create([
|
||||
'id' => 'llama',
|
||||
'name' => $this->randomString(),
|
||||
]);
|
||||
$role->save();
|
||||
|
||||
return $role;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'uuid' => $this->entity->uuid(),
|
||||
'weight' => 2,
|
||||
'langcode' => 'en',
|
||||
'status' => TRUE,
|
||||
'dependencies' => [],
|
||||
'id' => 'llama',
|
||||
'label' => NULL,
|
||||
'is_admin' => NULL,
|
||||
'permissions' => [],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
// @todo Update in https://www.drupal.org/node/2300677.
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleXmlAnonTest extends RoleResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleXmlBasicAuthTest extends RoleResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class RoleXmlCookieTest extends RoleResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserJsonAnonTest extends UserResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserJsonBasicAuthTest extends UserResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserJsonCookieTest extends UserResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
}
|
|
@ -0,0 +1,329 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
|
||||
abstract class UserResourceTestBase extends EntityResourceTestBase {
|
||||
|
||||
use BcTimestampNormalizerUnixTestTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $entityTypeId = 'user';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $patchProtectedFieldNames = [
|
||||
'changed' => NULL,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $labelFieldName = 'name';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $firstCreatedEntityId = 4;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $secondCreatedEntityId = 5;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
$this->grantPermissionsToTestedRole(['access user profiles']);
|
||||
break;
|
||||
case 'POST':
|
||||
case 'PATCH':
|
||||
case 'DELETE':
|
||||
$this->grantPermissionsToTestedRole(['administer users']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Llama" user.
|
||||
$user = User::create(['created' => 123456789]);
|
||||
$user->setUsername('Llama')
|
||||
->setChangedTime(123456789)
|
||||
->activate()
|
||||
->save();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createAnotherEntity() {
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = $this->entity->createDuplicate();
|
||||
$user->setUsername($user->label() . '_dupe');
|
||||
$user->save();
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedNormalizedEntity() {
|
||||
return [
|
||||
'uid' => [
|
||||
['value' => 3],
|
||||
],
|
||||
'uuid' => [
|
||||
['value' => $this->entity->uuid()],
|
||||
],
|
||||
'langcode' => [
|
||||
[
|
||||
'value' => 'en',
|
||||
],
|
||||
],
|
||||
'name' => [
|
||||
[
|
||||
'value' => 'Llama',
|
||||
],
|
||||
],
|
||||
'created' => [
|
||||
$this->formatExpectedTimestampItemValues(123456789),
|
||||
],
|
||||
'changed' => [
|
||||
$this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
|
||||
],
|
||||
'default_langcode' => [
|
||||
[
|
||||
'value' => TRUE,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getNormalizedPostEntity() {
|
||||
return [
|
||||
'name' => [
|
||||
[
|
||||
'value' => 'Dramallama',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests PATCHing security-sensitive base fields of the logged in account.
|
||||
*/
|
||||
public function testPatchDxForSecuritySensitiveBaseFields() {
|
||||
// The anonymous user is never allowed to modify itself.
|
||||
if (!static::$auth) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
$this->initAuthentication();
|
||||
$this->provisionEntityResource();
|
||||
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = static::$auth ? $this->account : User::load(0);
|
||||
// @todo Remove the array_diff_key() call in https://www.drupal.org/node/2821077.
|
||||
$original_normalization = array_diff_key($this->serializer->normalize($user, static::$format), ['created' => TRUE, 'changed' => TRUE, 'name' => TRUE]);
|
||||
|
||||
// Since this test must be performed by the user that is being modified,
|
||||
// we cannot use $this->getUrl().
|
||||
$url = $user->toUrl()->setOption('query', ['_format' => static::$format]);
|
||||
$request_options = [
|
||||
RequestOptions::HEADERS => ['Content-Type' => static::$mimeType],
|
||||
];
|
||||
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
|
||||
// Test case 1: changing email.
|
||||
$normalization = $original_normalization;
|
||||
$normalization['mail'] = [['value' => 'new-email@example.com']];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// DX: 422 when changing email without providing the password.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response, FALSE, FALSE, FALSE, FALSE);
|
||||
|
||||
$normalization['pass'] = [['existing' => 'wrong']];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// DX: 422 when changing email while providing a wrong password.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nmail: Your current password is missing or incorrect; it's required to change the Email.\n", $response, FALSE, FALSE, FALSE, FALSE);
|
||||
|
||||
$normalization['pass'] = [['existing' => $this->account->passRaw]];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// 200 for well-formed request.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
// Test case 2: changing password.
|
||||
$normalization = $original_normalization;
|
||||
$new_password = $this->randomString();
|
||||
$normalization['pass'] = [['value' => $new_password]];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// DX: 422 when changing password without providing the current password.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\npass: Your current password is missing or incorrect; it's required to change the Password.\n", $response, FALSE, FALSE, FALSE, FALSE);
|
||||
|
||||
$normalization['pass'][0]['existing'] = $this->account->pass_raw;
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// 200 for well-formed request.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
// Verify that we can log in with the new password.
|
||||
$this->assertRpcLogin($user->getAccountName(), $new_password);
|
||||
|
||||
// Update password in $this->account, prepare for future requests.
|
||||
$this->account->passRaw = $new_password;
|
||||
$this->initAuthentication();
|
||||
$request_options = [
|
||||
RequestOptions::HEADERS => ['Content-Type' => static::$mimeType],
|
||||
];
|
||||
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
|
||||
// Test case 3: changing name.
|
||||
$normalization = $original_normalization;
|
||||
$normalization['name'] = [['value' => 'Cooler Llama']];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// DX: 403 when modifying username without required permission.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field 'name'.", $response);
|
||||
|
||||
$this->grantPermissionsToTestedRole(['change own username']);
|
||||
|
||||
// 200 for well-formed request.
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
|
||||
// Verify that we can log in with the new username.
|
||||
$this->assertRpcLogin('Cooler Llama', $new_password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that logging in with the given username and password works.
|
||||
*
|
||||
* @param string $username
|
||||
* The username to log in with.
|
||||
* @param string $password
|
||||
* The password to log in with.
|
||||
*/
|
||||
protected function assertRpcLogin($username, $password) {
|
||||
$request_body = [
|
||||
'name' => $username,
|
||||
'pass' => $password,
|
||||
];
|
||||
$request_options = [
|
||||
RequestOptions::HEADERS => [],
|
||||
RequestOptions::BODY => $this->serializer->encode($request_body, 'json'),
|
||||
];
|
||||
$response = $this->request('POST', Url::fromRoute('user.login.http')->setRouteParameter('_format', 'json'), $request_options);
|
||||
$this->assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests PATCHing security-sensitive base fields to change other users.
|
||||
*/
|
||||
public function testPatchSecurityOtherUser() {
|
||||
// The anonymous user is never allowed to modify other users.
|
||||
if (!static::$auth) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
$this->initAuthentication();
|
||||
$this->provisionEntityResource();
|
||||
|
||||
/** @var \Drupal\user\UserInterface $user */
|
||||
$user = $this->account;
|
||||
$original_normalization = array_diff_key($this->serializer->normalize($user, static::$format), ['changed' => TRUE]);
|
||||
|
||||
// Since this test must be performed by the user that is being modified,
|
||||
// we cannot use $this->getUrl().
|
||||
$url = $user->toUrl()->setOption('query', ['_format' => static::$format]);
|
||||
$request_options = [
|
||||
RequestOptions::HEADERS => ['Content-Type' => static::$mimeType],
|
||||
];
|
||||
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
|
||||
|
||||
$normalization = $original_normalization;
|
||||
$normalization['mail'] = [['value' => 'new-email@example.com']];
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
|
||||
|
||||
// Try changing user 1's email.
|
||||
$user1 = [
|
||||
'mail' => [['value' => 'another_email_address@example.com']],
|
||||
'uid' => [['value' => 1]],
|
||||
'name' => [['value' => 'another_user_name']],
|
||||
'pass' => [['existing' => $this->account->passRaw]],
|
||||
'uuid' => [['value' => '2e9403a4-d8af-4096-a116-624710140be0']],
|
||||
] + $original_normalization;
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($user1, static::$format);
|
||||
$response = $this->request('PATCH', $url, $request_options);
|
||||
// Ensure the email address has not changed.
|
||||
$this->assertEquals('admin@example.com', $this->entityStorage->loadUnchanged(1)->getEmail());
|
||||
$this->assertResourceErrorResponse(403, "Access denied on updating field 'uid'. The entity ID cannot be changed.", $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {
|
||||
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
|
||||
switch ($method) {
|
||||
case 'GET':
|
||||
return "The 'access user profiles' permission is required and the user must be active.";
|
||||
case 'PATCH':
|
||||
return "You are not authorized to update this user entity.";
|
||||
case 'DELETE':
|
||||
return 'You are not authorized to delete this user entity.';
|
||||
default:
|
||||
return parent::getExpectedUnauthorizedAccessMessage($method);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessCacheability() {
|
||||
// @see \Drupal\user\UserAccessControlHandler::checkAccess()
|
||||
return parent::getExpectedUnauthorizedAccessCacheability()
|
||||
->addCacheTags(['user:3']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserXmlAnonTest extends UserResourceTestBase {
|
||||
|
||||
use AnonResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchDxForSecuritySensitiveBaseFields() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserXmlBasicAuthTest extends UserResourceTestBase {
|
||||
|
||||
use BasicAuthResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['basic_auth'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'basic_auth';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchDxForSecuritySensitiveBaseFields() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchSecurityOtherUser() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Rest;
|
||||
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* @group rest
|
||||
*/
|
||||
class UserXmlCookieTest extends UserResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
use XmlEntityNormalizationQuirksTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'xml';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'text/xml; charset=UTF-8';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchDxForSecuritySensitiveBaseFields() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testPatchSecurityOtherUser() {
|
||||
// Deserialization of the XML format is not supported.
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
|
||||
use Drupal\Tests\rest\Functional\ResourceTestBase;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use Drupal\Core\Test\AssertMailTrait;
|
||||
|
||||
/**
|
||||
* Tests user registration via REST resource.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class RestRegisterUserTest extends ResourceTestBase {
|
||||
|
||||
use CookieResourceTestTrait;
|
||||
|
||||
use AssertMailTrait {
|
||||
getMails as drupalGetMails;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $format = 'hal_json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $mimeType = 'application/hal+json';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $auth = 'cookie';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $resourceConfigId = 'user_registration';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['hal', 'user'];
|
||||
|
||||
const USER_EMAIL_DOMAIN = '@example.com';
|
||||
|
||||
const TEST_EMAIL_DOMAIN = 'simpletest@example.com';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$auth = isset(static::$auth) ? [static::$auth] : [];
|
||||
$this->provisionResource([static::$format], $auth);
|
||||
|
||||
$this->setUpAuthorization('POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that only anonymous users can register users.
|
||||
*/
|
||||
public function testRegisterUser() {
|
||||
$config = $this->config('user.settings');
|
||||
|
||||
// Test out different setting User Registration and Email Verification.
|
||||
// Allow visitors to register with no email verification.
|
||||
$config->set('register', USER_REGISTER_VISITORS);
|
||||
$config->set('verify_mail', 0);
|
||||
$config->save();
|
||||
$user = $this->registerUser('Palmer.Eldritch');
|
||||
$this->assertFalse($user->isBlocked());
|
||||
$this->assertFalse(empty($user->getPassword()));
|
||||
$email_count = count($this->drupalGetMails());
|
||||
|
||||
$this->assertEquals($email_count, 0);
|
||||
|
||||
// Attempt to register without sending a password.
|
||||
$response = $this->registerRequest('Rick.Deckard', FALSE);
|
||||
$this->assertResourceErrorResponse(422, "No password provided.", $response);
|
||||
|
||||
// Attempt to register with a password when e-mail verification is on.
|
||||
$config->set('register', USER_REGISTER_VISITORS);
|
||||
$config->set('verify_mail', 1);
|
||||
$config->save();
|
||||
$response = $this->registerRequest('Estraven', TRUE);
|
||||
$this->assertResourceErrorResponse(422, 'A Password cannot be specified. It will be generated on login.', $response);
|
||||
|
||||
// Allow visitors to register with email verification.
|
||||
$config->set('register', USER_REGISTER_VISITORS);
|
||||
$config->set('verify_mail', 1);
|
||||
$config->save();
|
||||
$name = 'Jason.Taverner';
|
||||
$user = $this->registerUser($name, FALSE);
|
||||
$this->assertTrue(empty($user->getPassword()));
|
||||
$this->assertTrue($user->isBlocked());
|
||||
$this->resetAll();
|
||||
|
||||
$this->assertMailString('body', 'You may now log in by clicking this link', 1);
|
||||
|
||||
// Allow visitors to register with Admin approval and no email verification.
|
||||
$config->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
|
||||
$config->set('verify_mail', 0);
|
||||
$config->save();
|
||||
$name = 'Argaven';
|
||||
$user = $this->registerUser($name);
|
||||
$this->resetAll();
|
||||
$this->assertFalse(empty($user->getPassword()));
|
||||
$this->assertTrue($user->isBlocked());
|
||||
$this->assertMailString('body', 'Your application for an account is', 2);
|
||||
$this->assertMailString('body', 'Argaven has applied for an account', 2);
|
||||
|
||||
// Allow visitors to register with Admin approval and e-mail verification.
|
||||
$config->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
|
||||
$config->set('verify_mail', 1);
|
||||
$config->save();
|
||||
$name = 'Bob.Arctor';
|
||||
$user = $this->registerUser($name, FALSE);
|
||||
$this->resetAll();
|
||||
$this->assertTrue(empty($user->getPassword()));
|
||||
$this->assertTrue($user->isBlocked());
|
||||
|
||||
$this->assertMailString('body', 'Your application for an account is', 2);
|
||||
$this->assertMailString('body', 'Bob.Arctor has applied for an account', 2);
|
||||
|
||||
// Verify that an authenticated user cannot register a new user, despite
|
||||
// being granted permission to do so because only anonymous users can
|
||||
// register themselves, authenticated users with the necessary permissions
|
||||
// can POST a new user to the "user" REST resource.
|
||||
$this->initAuthentication();
|
||||
$response = $this->registerRequest($this->account->getAccountName());
|
||||
$this->assertResourceErrorResponse(403, "Only anonymous users can register a user.", $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the request body.
|
||||
*
|
||||
* @param string $name
|
||||
* Name.
|
||||
* @param bool $include_password
|
||||
* Include Password.
|
||||
* @param bool $include_email
|
||||
* Include Email.
|
||||
*
|
||||
* @return array
|
||||
* Return the request body.
|
||||
*/
|
||||
protected function createRequestBody($name, $include_password = TRUE, $include_email = TRUE) {
|
||||
global $base_url;
|
||||
$request_body = [
|
||||
'_links' => ['type' => ["href" => $base_url . "/rest/type/user/user"]],
|
||||
'langcode' => [['value' => 'en']],
|
||||
'name' => [['value' => $name]],
|
||||
];
|
||||
|
||||
if ($include_email) {
|
||||
$request_body['mail'] = [['value' => $name . self::USER_EMAIL_DOMAIN]];
|
||||
}
|
||||
|
||||
if ($include_password) {
|
||||
$request_body['pass']['value'] = 'SuperSecretPassword';
|
||||
}
|
||||
|
||||
return $request_body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to generate the request body.
|
||||
*
|
||||
* @param array $request_body
|
||||
* The request body array.
|
||||
*
|
||||
* @return array
|
||||
* Return the request options.
|
||||
*/
|
||||
protected function createRequestOptions(array $request_body) {
|
||||
$request_options = $this->getAuthenticationRequestOptions('POST');
|
||||
$request_options[RequestOptions::BODY] = $this->serializer->encode($request_body, static::$format);
|
||||
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
|
||||
|
||||
return $request_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a user via REST resource.
|
||||
*
|
||||
* @param string $name
|
||||
* User name.
|
||||
* @param bool $include_password
|
||||
* Include the password.
|
||||
* @param bool $include_email
|
||||
* Include the email?
|
||||
*
|
||||
* @return bool|\Drupal\user\Entity\User
|
||||
* Return bool or the user.
|
||||
*/
|
||||
protected function registerUser($name, $include_password = TRUE, $include_email = TRUE) {
|
||||
// Verify that an anonymous user can register.
|
||||
$response = $this->registerRequest($name, $include_password, $include_email);
|
||||
$this->assertResourceResponse(200, FALSE, $response);
|
||||
$user = user_load_by_name($name);
|
||||
$this->assertFalse(empty($user), 'User was create as expected');
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a REST user registration request.
|
||||
*
|
||||
* @param string $name
|
||||
* The name.
|
||||
* @param bool $include_password
|
||||
* Include the password?
|
||||
* @param bool $include_email
|
||||
* Include the email?
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
* Return the Response.
|
||||
*/
|
||||
protected function registerRequest($name, $include_password = TRUE, $include_email = TRUE) {
|
||||
|
||||
$user_register_url = Url::fromRoute('user.register')
|
||||
->setRouteParameter('_format', static::$format);
|
||||
$request_body = $this->createRequestBody($name, $include_password, $include_email);
|
||||
$request_options = $this->createRequestOptions($request_body);
|
||||
$response = $this->request('POST', $user_register_url, $request_options);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUpAuthorization($method) {
|
||||
switch ($method) {
|
||||
case 'POST':
|
||||
$this->grantPermissionsToAuthenticatedRole(['restful post user_registration']);
|
||||
$this->grantPermissionsToAnonymousRole(['restful post user_registration']);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \UnexpectedValueException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function assertNormalizationEdgeCases($method, Url $url, array $request_options) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessMessage($method) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedBcUnauthorizedAccessMessage($method) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedUnauthorizedAccessCacheability() {}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Update;
|
||||
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
|
||||
/**
|
||||
* Tests user email token upgrade path.
|
||||
*
|
||||
* @group Update
|
||||
* @group legacy
|
||||
*/
|
||||
class UserUpdateEmailToken extends UpdatePathTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
|
||||
__DIR__ . '/../../../fixtures/update/drupal-8.user-email-token-2587275.php',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that email token in status_blocked of user.mail is updated.
|
||||
*/
|
||||
public function testEmailToken() {
|
||||
$mail = \Drupal::config('user.mail')->get('status_blocked');
|
||||
$this->assertTrue(strpos($mail['body'], '[site:account-name]'));
|
||||
$this->runUpdates();
|
||||
$mail = \Drupal::config('user.mail')->get('status_blocked');
|
||||
$this->assertFalse(strpos($mail['body'], '[site:account-name]'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Update;
|
||||
|
||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||
|
||||
/**
|
||||
* Tests user permissions sort upgrade path.
|
||||
*
|
||||
* @group Update
|
||||
* @group legacy
|
||||
*/
|
||||
class UserUpdateOrderPermissionsTest extends UpdatePathTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setDatabaseDumpFiles() {
|
||||
$this->databaseDumpFiles = [
|
||||
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that permissions are ordered by machine name.
|
||||
*/
|
||||
public function testPermissionsOrder() {
|
||||
$authenticated = \Drupal::config('user.role.authenticated');
|
||||
$permissions = $authenticated->get('permissions');
|
||||
sort($permissions);
|
||||
$this->assertNotSame($permissions, $authenticated->get('permissions'));
|
||||
|
||||
$this->runUpdates();
|
||||
$authenticated = \Drupal::config('user.role.authenticated');
|
||||
$this->assertSame($permissions, $authenticated->get('permissions'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests user-account links.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserAccountLinksTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* 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($label[0]->getText(), "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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests users' ability to change their own administration language.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserAdminLanguageTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* A user with permission to access admin pages and administer languages.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* A non-administrator user for this test.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $regularUser;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['user', 'language', 'language_test'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
// User to add and remove language.
|
||||
$this->adminUser = $this->drupalCreateUser(['administer languages', 'access administration pages']);
|
||||
// User to check non-admin access.
|
||||
$this->regularUser = $this->drupalCreateUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that admin language is not configurable in single language sites.
|
||||
*/
|
||||
public function testUserAdminLanguageConfigurationNotAvailableWithOnlyOneLanguage() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->setLanguageNegotiation();
|
||||
$path = 'user/' . $this->adminUser->id() . '/edit';
|
||||
$this->drupalGet($path);
|
||||
// Ensure administration pages language settings widget is not available.
|
||||
$this->assertNoFieldByXPath($this->constructFieldXpath('id', 'edit-preferred-admin-langcode'), NULL, 'Administration pages language selector not available.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that admin language negotiation is configurable only if enabled.
|
||||
*/
|
||||
public function testUserAdminLanguageConfigurationAvailableWithAdminLanguageNegotiation() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->addCustomLanguage();
|
||||
$path = 'user/' . $this->adminUser->id() . '/edit';
|
||||
|
||||
// Checks with user administration pages language negotiation disabled.
|
||||
$this->drupalGet($path);
|
||||
// Ensure administration pages language settings widget is not available.
|
||||
$this->assertNoFieldByXPath($this->constructFieldXpath('id', 'edit-preferred-admin-langcode'), NULL, 'Administration pages language selector not available.');
|
||||
|
||||
// Checks with user administration pages language negotiation enabled.
|
||||
$this->setLanguageNegotiation();
|
||||
$this->drupalGet($path);
|
||||
// Ensure administration pages language settings widget is available.
|
||||
$this->assertFieldByXPath($this->constructFieldXpath('id', 'edit-preferred-admin-langcode'), NULL, 'Administration pages language selector is available.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the admin language is configurable only for administrators.
|
||||
*
|
||||
* If a user has the permission "access administration pages", they should
|
||||
* be able to see the setting to pick the language they want those pages in.
|
||||
*
|
||||
* If a user does not have that permission, it would confusing for them to
|
||||
* have a setting for pages they cannot access, so they should not be able to
|
||||
* set a language for those pages.
|
||||
*/
|
||||
public function testUserAdminLanguageConfigurationAvailableIfAdminLanguageNegotiationIsEnabled() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
// Adds a new language, because with only one language, setting won't show.
|
||||
$this->addCustomLanguage();
|
||||
$this->setLanguageNegotiation();
|
||||
$path = 'user/' . $this->adminUser->id() . '/edit';
|
||||
$this->drupalGet($path);
|
||||
// Ensure administration pages language setting is visible for admin.
|
||||
$this->assertFieldByXPath($this->constructFieldXpath('id', 'edit-preferred-admin-langcode'), NULL, 'Administration pages language selector available for admins.');
|
||||
|
||||
// Ensure administration pages language setting is hidden for non-admins.
|
||||
$this->drupalLogin($this->regularUser);
|
||||
$path = 'user/' . $this->regularUser->id() . '/edit';
|
||||
$this->drupalGet($path);
|
||||
$this->assertNoFieldByXPath($this->constructFieldXpath('id', 'edit-preferred-admin-langcode'), NULL, 'Administration pages language selector not available for regular user.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the actual language negotiation.
|
||||
*/
|
||||
public function testActualNegotiation() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->addCustomLanguage();
|
||||
$this->setLanguageNegotiation();
|
||||
|
||||
// Even though we have admin language negotiation, so long as the user has
|
||||
// no preference set, negotiation will fall back further.
|
||||
$path = 'user/' . $this->adminUser->id() . '/edit';
|
||||
$this->drupalGet($path);
|
||||
$this->assertText('Language negotiation method: language-default');
|
||||
$this->drupalGet('xx/' . $path);
|
||||
$this->assertText('Language negotiation method: language-url');
|
||||
|
||||
// Set a preferred language code for the user.
|
||||
$edit = [];
|
||||
$edit['preferred_admin_langcode'] = 'xx';
|
||||
$this->drupalPostForm($path, $edit, t('Save'));
|
||||
|
||||
// Test negotiation with the URL method first. The admin method will only
|
||||
// be used if the URL method did not match.
|
||||
$this->drupalGet($path);
|
||||
$this->assertText('Language negotiation method: language-user-admin');
|
||||
$this->drupalGet('xx/' . $path);
|
||||
$this->assertText('Language negotiation method: language-url');
|
||||
|
||||
// Test negotiation with the admin language method first. The admin method
|
||||
// will be used at all times.
|
||||
$this->setLanguageNegotiation(TRUE);
|
||||
$this->drupalGet($path);
|
||||
$this->assertText('Language negotiation method: language-user-admin');
|
||||
$this->drupalGet('xx/' . $path);
|
||||
$this->assertText('Language negotiation method: language-user-admin');
|
||||
|
||||
// Unset the preferred language code for the user.
|
||||
$edit = [];
|
||||
$edit['preferred_admin_langcode'] = '';
|
||||
$this->drupalPostForm($path, $edit, t('Save'));
|
||||
$this->drupalGet($path);
|
||||
$this->assertText('Language negotiation method: language-default');
|
||||
$this->drupalGet('xx/' . $path);
|
||||
$this->assertText('Language negotiation method: language-url');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the User interface negotiation detection method.
|
||||
*
|
||||
* Enables the "Account preference for administration pages" language
|
||||
* detection method for the User interface language negotiation type.
|
||||
*
|
||||
* @param bool $admin_first
|
||||
* Whether the admin negotiation should be first.
|
||||
*/
|
||||
public function setLanguageNegotiation($admin_first = FALSE) {
|
||||
$edit = [
|
||||
'language_interface[enabled][language-user-admin]' => TRUE,
|
||||
'language_interface[enabled][language-url]' => TRUE,
|
||||
'language_interface[weight][language-user-admin]' => ($admin_first ? -12 : -8),
|
||||
'language_interface[weight][language-url]' => -10,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for adding a custom language.
|
||||
*/
|
||||
public function addCustomLanguage() {
|
||||
$langcode = 'xx';
|
||||
// The English name for the language.
|
||||
$name = $this->randomMachineName(16);
|
||||
$edit = [
|
||||
'predefined_langcode' => 'custom',
|
||||
'langcode' => $langcode,
|
||||
'label' => $name,
|
||||
'direction' => LanguageInterface::DIRECTION_LTR,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Tests the user admin listing if views is not enabled.
|
||||
*
|
||||
* @group user
|
||||
* @see user_admin_account()
|
||||
*/
|
||||
class UserAdminListingTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$account_columns = $account->findAll('css', 'td');
|
||||
$name = $account_columns[0]->getText();
|
||||
$roles = [];
|
||||
$account_roles = $account_columns[2]->findAll('css', 'td div ul li');
|
||||
if (!empty($account_roles)) {
|
||||
foreach ($account_roles as $element) {
|
||||
$roles[] = $element->getText();
|
||||
}
|
||||
}
|
||||
|
||||
$result_accounts[$name] = [
|
||||
'name' => $name,
|
||||
'status' => $account_columns[1]->getText(),
|
||||
'roles' => $roles,
|
||||
'member_for' => $account_columns[3]->getText(),
|
||||
'last_access' => $account_columns[4]->getText(),
|
||||
];
|
||||
}
|
||||
|
||||
$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".');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Test\AssertMailTrait;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Tests user administration page functionality.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserAdminTest extends BrowserTestBase {
|
||||
|
||||
use AssertMailTrait {
|
||||
getMails as drupalGetMails;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(), $result[0]->find('xpath', '/td[2]/span')->getText(), '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(), $result[0]->find('xpath', '/td[2]/span')->getText(), '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');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\dynamic_page_cache\EventSubscriber\DynamicPageCacheSubscriber;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests user blocks.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserBlocksTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['block', 'views'];
|
||||
|
||||
/**
|
||||
* A user with the 'administer blocks' permission.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->adminUser = $this->drupalCreateUser(['administer blocks']);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalPlaceBlock('user_login_block');
|
||||
$this->drupalLogout($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that user login block is hidden from user/login.
|
||||
*/
|
||||
public function testUserLoginBlockVisibility() {
|
||||
// Array keyed list where key being the URL address and value being expected
|
||||
// visibility as boolean type.
|
||||
$paths = [
|
||||
'node' => TRUE,
|
||||
'user/login' => FALSE,
|
||||
'user/register' => TRUE,
|
||||
'user/password' => TRUE,
|
||||
];
|
||||
foreach ($paths as $path => $expected_visibility) {
|
||||
$this->drupalGet($path);
|
||||
$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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the user login block.
|
||||
*/
|
||||
public function testUserLoginBlock() {
|
||||
// Create a user with some permission that anonymous users lack.
|
||||
$user = $this->drupalCreateUser(['administer permissions']);
|
||||
|
||||
// Log in using the block.
|
||||
$edit = [];
|
||||
$edit['name'] = $user->getUsername();
|
||||
$edit['pass'] = $user->passRaw;
|
||||
$this->drupalPostForm('admin/people/permissions', $edit, t('Log in'));
|
||||
$this->assertNoText(t('User login'), 'Logged in.');
|
||||
|
||||
// Check that we are still on the same page.
|
||||
$this->assertUrl(\Drupal::url('user.admin_permissions', [], ['absolute' => TRUE]), [], 'Still on the same page after login for access denied page');
|
||||
|
||||
// Now, log out and repeat with a non-403 page.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('filter/tips');
|
||||
$this->assertEqual('MISS', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER));
|
||||
$this->drupalPostForm(NULL, $edit, t('Log in'));
|
||||
$this->assertNoText(t('User login'), 'Logged in.');
|
||||
$this->assertPattern('!<title.*?' . t('Compose tips') . '.*?</title>!', 'Still on the same page after login for allowed page');
|
||||
|
||||
// Log out again and repeat with a non-403 page including query arguments.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('filter/tips', ['query' => ['foo' => 'bar']]);
|
||||
$this->assertEqual('HIT', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER));
|
||||
$this->drupalPostForm(NULL, $edit, t('Log in'));
|
||||
$this->assertNoText(t('User login'), 'Logged in.');
|
||||
$this->assertPattern('!<title.*?' . t('Compose tips') . '.*?</title>!', 'Still on the same page after login for allowed page');
|
||||
$this->assertTrue(strpos($this->getUrl(), '/filter/tips?foo=bar') !== FALSE, 'Correct query arguments are displayed after login');
|
||||
|
||||
// Repeat with different query arguments.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('filter/tips', ['query' => ['foo' => 'baz']]);
|
||||
$this->assertEqual('HIT', $this->drupalGetHeader(DynamicPageCacheSubscriber::HEADER));
|
||||
$this->drupalPostForm(NULL, $edit, t('Log in'));
|
||||
$this->assertNoText(t('User login'), 'Logged in.');
|
||||
$this->assertPattern('!<title.*?' . t('Compose tips') . '.*?</title>!', 'Still on the same page after login for allowed page');
|
||||
$this->assertTrue(strpos($this->getUrl(), '/filter/tips?foo=baz') !== FALSE, 'Correct query arguments are displayed after login');
|
||||
|
||||
// Check that the user login block is not vulnerable to information
|
||||
// disclosure to third party sites.
|
||||
$this->drupalLogout();
|
||||
$this->drupalPostForm('http://example.com/', $edit, t('Log in'), ['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 = [];
|
||||
$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?'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the access column for a user.
|
||||
*/
|
||||
private function updateAccess($uid, $access = REQUEST_TIME) {
|
||||
db_update('users_field_data')
|
||||
->condition('uid', $uid)
|
||||
->fields(['access' => $access])
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Tests the User entity's cache tags.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserCacheTagsTest extends EntityWithUriCacheTagsTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Give anonymous users permission to view user profiles, so that we can
|
||||
// verify the cache tags of cached versions of user profile pages.
|
||||
$user_role = Role::load(RoleInterface::ANONYMOUS_ID);
|
||||
$user_role->grantPermission('access user profiles');
|
||||
$user_role->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createEntity() {
|
||||
// Create a "Llama" user.
|
||||
$user = User::create([
|
||||
'name' => 'Llama',
|
||||
'status' => TRUE,
|
||||
]);
|
||||
$user->save();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAdditionalCacheTagsForEntityListing() {
|
||||
return ['user:0', 'user:1'];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,601 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\comment\CommentInterface;
|
||||
use Drupal\comment\Entity\Comment;
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Ensure that account cancellation methods work as expected.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserCancelTest extends BrowserTestBase {
|
||||
|
||||
use CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['node', 'comment'];
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to cancel account without permission.
|
||||
*/
|
||||
public function testUserCancelWithoutPermission() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save();
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
|
||||
// Create a user.
|
||||
$account = $this->drupalCreateUser([]);
|
||||
$this->drupalLogin($account);
|
||||
// Load a real user object.
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
|
||||
// Create a node.
|
||||
$node = $this->drupalCreateNode(['uid' => $account->id()]);
|
||||
|
||||
// Attempt to cancel account.
|
||||
$this->drupalGet('user/' . $account->id() . '/edit');
|
||||
$this->assertNoRaw(t('Cancel account'), 'No cancel account button displayed.');
|
||||
|
||||
// Attempt bogus account cancellation request confirmation.
|
||||
$timestamp = $account->getLastLoginTime();
|
||||
$this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
|
||||
$this->assertResponse(403, 'Bogus cancelling request rejected.');
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
$this->assertTrue($account->isActive(), 'User account was not canceled.');
|
||||
|
||||
// Confirm user's content has not been altered.
|
||||
$node_storage->resetCache([$node->id()]);
|
||||
$test_node = $node_storage->load($node->id());
|
||||
$this->assertTrue(($test_node->getOwnerId() == $account->id() && $test_node->isPublished()), 'Node of the user has not been altered.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test ability to change the permission for canceling users.
|
||||
*/
|
||||
public function testUserCancelChangePermission() {
|
||||
\Drupal::service('module_installer')->install(['user_form_test']);
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save();
|
||||
|
||||
// Create a regular user.
|
||||
$account = $this->drupalCreateUser([]);
|
||||
|
||||
$admin_user = $this->drupalCreateUser(['cancel other accounts']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Delete regular user.
|
||||
$this->drupalPostForm('user_form_test_cancel/' . $account->id(), [], t('Cancel account'));
|
||||
|
||||
// Confirm deletion.
|
||||
$this->assertRaw(t('%name has been deleted.', ['%name' => $account->getUsername()]), 'User deleted.');
|
||||
$this->assertFalse(User::load($account->id()), 'User is not found in the database.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that user account for uid 1 cannot be cancelled.
|
||||
*
|
||||
* This should never be possible, or the site owner would become unable to
|
||||
* administer the site.
|
||||
*/
|
||||
public function testUserCancelUid1() {
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
|
||||
\Drupal::service('module_installer')->install(['views']);
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
|
||||
// Try to cancel uid 1's account with a different user.
|
||||
$admin_user = $this->drupalCreateUser(['administer users']);
|
||||
$this->drupalLogin($admin_user);
|
||||
$edit = [
|
||||
'action' => 'user_cancel_user_action',
|
||||
'user_bulk_form[0]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/people', $edit, t('Apply to selected items'));
|
||||
|
||||
// Verify that uid 1's account was not cancelled.
|
||||
$user_storage->resetCache([1]);
|
||||
$user1 = $user_storage->load(1);
|
||||
$this->assertTrue($user1->isActive(), 'User #1 still exists and is not blocked.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt invalid account cancellations.
|
||||
*/
|
||||
public function testUserCancelInvalid() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save();
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
|
||||
// Create a user.
|
||||
$account = $this->drupalCreateUser(['cancel account']);
|
||||
$this->drupalLogin($account);
|
||||
// Load a real user object.
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
|
||||
// Create a node.
|
||||
$node = $this->drupalCreateNode(['uid' => $account->id()]);
|
||||
|
||||
// Attempt to cancel account.
|
||||
$this->drupalPostForm('user/' . $account->id() . '/edit', NULL, t('Cancel account'));
|
||||
|
||||
// Confirm account cancellation.
|
||||
$timestamp = time();
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('A confirmation request to cancel your account has been sent to your email address.'), 'Account cancellation request mailed message displayed.');
|
||||
|
||||
// Attempt bogus account cancellation request confirmation.
|
||||
$bogus_timestamp = $timestamp + 60;
|
||||
$this->drupalGet("user/" . $account->id() . "/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account, $bogus_timestamp));
|
||||
$this->assertText(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'Bogus cancelling request rejected.');
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
$this->assertTrue($account->isActive(), 'User account was not canceled.');
|
||||
|
||||
// Attempt expired account cancellation request confirmation.
|
||||
$bogus_timestamp = $timestamp - 86400 - 60;
|
||||
$this->drupalGet("user/" . $account->id() . "/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account, $bogus_timestamp));
|
||||
$this->assertText(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'Expired cancel account request rejected.');
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
$this->assertTrue($account->isActive(), 'User account was not canceled.');
|
||||
|
||||
// Confirm user's content has not been altered.
|
||||
$node_storage->resetCache([$node->id()]);
|
||||
$test_node = $node_storage->load($node->id());
|
||||
$this->assertTrue(($test_node->getOwnerId() == $account->id() && $test_node->isPublished()), 'Node of the user has not been altered.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable account and keep all content.
|
||||
*/
|
||||
public function testUserBlock() {
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_block')->save();
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
|
||||
// Create a user.
|
||||
$web_user = $this->drupalCreateUser(['cancel account']);
|
||||
$this->drupalLogin($web_user);
|
||||
|
||||
// Load a real user object.
|
||||
$user_storage->resetCache([$web_user->id()]);
|
||||
$account = $user_storage->load($web_user->id());
|
||||
|
||||
// Attempt to cancel account.
|
||||
$this->drupalGet('user/' . $account->id() . '/edit');
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
|
||||
$this->assertText(t('Your account will be blocked and you will no longer be able to log in. All of your content will remain attributed to your username.'), 'Informs that all content will be remain as is.');
|
||||
$this->assertNoText(t('Select the method to cancel the account above.'), 'Does not allow user to select account cancellation method.');
|
||||
|
||||
// Confirm account cancellation.
|
||||
$timestamp = time();
|
||||
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('A confirmation request to cancel your account has been sent to your email address.'), 'Account cancellation request mailed message displayed.');
|
||||
|
||||
// Confirm account cancellation request.
|
||||
$this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
$this->assertTrue($account->isBlocked(), 'User has been blocked.');
|
||||
|
||||
// Confirm that the confirmation message made it through to the end user.
|
||||
$this->assertRaw(t('%name has been disabled.', ['%name' => $account->getUsername()]), "Confirmation message displayed to user.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable account and unpublish all content.
|
||||
*/
|
||||
public function testUserBlockUnpublish() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_block_unpublish')->save();
|
||||
// Create comment field on page.
|
||||
$this->addDefaultCommentField('node', 'page');
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
|
||||
// Create a user.
|
||||
$account = $this->drupalCreateUser(['cancel account']);
|
||||
$this->drupalLogin($account);
|
||||
// Load a real user object.
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
|
||||
// Create a node with two revisions.
|
||||
$node = $this->drupalCreateNode(['uid' => $account->id()]);
|
||||
$settings = get_object_vars($node);
|
||||
$settings['revision'] = 1;
|
||||
$node = $this->drupalCreateNode($settings);
|
||||
|
||||
// Add a comment to the page.
|
||||
$comment_subject = $this->randomMachineName(8);
|
||||
$comment_body = $this->randomMachineName(8);
|
||||
$comment = Comment::create([
|
||||
'subject' => $comment_subject,
|
||||
'comment_body' => $comment_body,
|
||||
'entity_id' => $node->id(),
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'comment',
|
||||
'status' => CommentInterface::PUBLISHED,
|
||||
'uid' => $account->id(),
|
||||
]);
|
||||
$comment->save();
|
||||
|
||||
// Attempt to cancel account.
|
||||
$this->drupalGet('user/' . $account->id() . '/edit');
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
|
||||
$this->assertText(t('Your account will be blocked and you will no longer be able to log in. All of your content will be hidden from everyone but administrators.'), 'Informs that all content will be unpublished.');
|
||||
|
||||
// Confirm account cancellation.
|
||||
$timestamp = time();
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('A confirmation request to cancel your account has been sent to your email address.'), 'Account cancellation request mailed message displayed.');
|
||||
|
||||
// Confirm account cancellation request.
|
||||
$this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
|
||||
// Confirm that the user was redirected to the front page.
|
||||
$this->assertSession()->addressEquals('');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
// Confirm that the confirmation message made it through to the end user.
|
||||
$this->assertRaw(t('%name has been disabled.', ['%name' => $account->getUsername()]), "Confirmation message displayed to user.");
|
||||
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
$this->assertTrue($account->isBlocked(), 'User has been blocked.');
|
||||
|
||||
// Confirm user's content has been unpublished.
|
||||
$node_storage->resetCache([$node->id()]);
|
||||
$test_node = $node_storage->load($node->id());
|
||||
$this->assertFalse($test_node->isPublished(), 'Node of the user has been unpublished.');
|
||||
$test_node = node_revision_load($node->getRevisionId());
|
||||
$this->assertFalse($test_node->isPublished(), 'Node revision of the user has been unpublished.');
|
||||
|
||||
$storage = \Drupal::entityManager()->getStorage('comment');
|
||||
$storage->resetCache([$comment->id()]);
|
||||
$comment = $storage->load($comment->id());
|
||||
$this->assertFalse($comment->isPublished(), 'Comment of the user has been unpublished.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete account and anonymize all content.
|
||||
*/
|
||||
public function testUserAnonymize() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save();
|
||||
// Create comment field on page.
|
||||
$this->addDefaultCommentField('node', 'page');
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
|
||||
// Create a user.
|
||||
$account = $this->drupalCreateUser(['cancel account']);
|
||||
$this->drupalLogin($account);
|
||||
// Load a real user object.
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
|
||||
// Create a simple node.
|
||||
$node = $this->drupalCreateNode(['uid' => $account->id()]);
|
||||
|
||||
// Add a comment to the page.
|
||||
$comment_subject = $this->randomMachineName(8);
|
||||
$comment_body = $this->randomMachineName(8);
|
||||
$comment = Comment::create([
|
||||
'subject' => $comment_subject,
|
||||
'comment_body' => $comment_body,
|
||||
'entity_id' => $node->id(),
|
||||
'entity_type' => 'node',
|
||||
'field_name' => 'comment',
|
||||
'status' => CommentInterface::PUBLISHED,
|
||||
'uid' => $account->id(),
|
||||
]);
|
||||
$comment->save();
|
||||
|
||||
// Create a node with two revisions, the initial one belonging to the
|
||||
// cancelling user.
|
||||
$revision_node = $this->drupalCreateNode(['uid' => $account->id()]);
|
||||
$revision = $revision_node->getRevisionId();
|
||||
$settings = get_object_vars($revision_node);
|
||||
$settings['revision'] = 1;
|
||||
// Set new/current revision to someone else.
|
||||
$settings['uid'] = 1;
|
||||
$revision_node = $this->drupalCreateNode($settings);
|
||||
|
||||
// Attempt to cancel account.
|
||||
$this->drupalGet('user/' . $account->id() . '/edit');
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
|
||||
$this->assertRaw(t('Your account will be removed and all account information deleted. All of your content will be assigned to the %anonymous-name user.', ['%anonymous-name' => $this->config('user.settings')->get('anonymous')]), 'Informs that all content will be attributed to anonymous account.');
|
||||
|
||||
// Confirm account cancellation.
|
||||
$timestamp = time();
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('A confirmation request to cancel your account has been sent to your email address.'), 'Account cancellation request mailed message displayed.');
|
||||
|
||||
// Confirm account cancellation request.
|
||||
$this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$this->assertFalse($user_storage->load($account->id()), 'User is not found in the database.');
|
||||
|
||||
// Confirm that user's content has been attributed to anonymous user.
|
||||
$anonymous_user = User::getAnonymousUser();
|
||||
$node_storage->resetCache([$node->id()]);
|
||||
$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->getRevisionUser()->id() == 0 && $test_node->isPublished()), 'Node revision of the user has been attributed to anonymous user.');
|
||||
$node_storage->resetCache([$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.");
|
||||
|
||||
$storage = \Drupal::entityManager()->getStorage('comment');
|
||||
$storage->resetCache([$comment->id()]);
|
||||
$test_comment = $storage->load($comment->id());
|
||||
$this->assertTrue(($test_comment->getOwnerId() == 0 && $test_comment->isPublished()), 'Comment of the user has been attributed to anonymous user.');
|
||||
$this->assertEqual($test_comment->getAuthorName(), $anonymous_user->getDisplayName(), 'Comment of the user has been attributed to anonymous user name.');
|
||||
|
||||
// Confirm that the confirmation message made it through to the end user.
|
||||
$this->assertRaw(t('%name has been deleted.', ['%name' => $account->getUsername()]), "Confirmation message displayed to user.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete account and anonymize all content using a batch process.
|
||||
*/
|
||||
public function testUserAnonymizeBatch() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save();
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
|
||||
// Create a user.
|
||||
$account = $this->drupalCreateUser(['cancel account']);
|
||||
$this->drupalLogin($account);
|
||||
// Load a real user object.
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
|
||||
// Create 11 nodes in order to trigger batch processing in
|
||||
// node_mass_update().
|
||||
$nodes = [];
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
$node = $this->drupalCreateNode(['uid' => $account->id()]);
|
||||
$nodes[$node->id()] = $node;
|
||||
}
|
||||
|
||||
// Attempt to cancel account.
|
||||
$this->drupalGet('user/' . $account->id() . '/edit');
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
|
||||
$this->assertRaw(t('Your account will be removed and all account information deleted. All of your content will be assigned to the %anonymous-name user.', ['%anonymous-name' => $this->config('user.settings')->get('anonymous')]), 'Informs that all content will be attributed to anonymous account.');
|
||||
|
||||
// Confirm account cancellation.
|
||||
$timestamp = time();
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('A confirmation request to cancel your account has been sent to your email address.'), 'Account cancellation request mailed message displayed.');
|
||||
|
||||
// Confirm account cancellation request.
|
||||
$this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$this->assertFalse($user_storage->load($account->id()), 'User is not found in the database.');
|
||||
|
||||
// Confirm that user's content has been attributed to anonymous user.
|
||||
$node_storage->resetCache(array_keys($nodes));
|
||||
$test_nodes = $node_storage->loadMultiple(array_keys($nodes));
|
||||
foreach ($test_nodes as $test_node) {
|
||||
$this->assertTrue(($test_node->getOwnerId() == 0 && $test_node->isPublished()), 'Node ' . $test_node->id() . ' of the user has been attributed to anonymous user.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete account and remove all content.
|
||||
*/
|
||||
public function testUserDelete() {
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_delete')->save();
|
||||
\Drupal::service('module_installer')->install(['comment']);
|
||||
$this->resetAll();
|
||||
$this->addDefaultCommentField('node', 'page');
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
|
||||
// Create a user.
|
||||
$account = $this->drupalCreateUser(['cancel account', 'post comments', 'skip comment approval']);
|
||||
$this->drupalLogin($account);
|
||||
// Load a real user object.
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
|
||||
// Create a simple node.
|
||||
$node = $this->drupalCreateNode(['uid' => $account->id()]);
|
||||
|
||||
// Create comment.
|
||||
$edit = [];
|
||||
$edit['subject[0][value]'] = $this->randomMachineName(8);
|
||||
$edit['comment_body[0][value]'] = $this->randomMachineName(16);
|
||||
|
||||
$this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit, t('Preview'));
|
||||
$this->drupalPostForm(NULL, [], t('Save'));
|
||||
$this->assertText(t('Your comment has been posted.'));
|
||||
$comments = entity_load_multiple_by_properties('comment', ['subject' => $edit['subject[0][value]']]);
|
||||
$comment = reset($comments);
|
||||
$this->assertTrue($comment->id(), 'Comment found.');
|
||||
|
||||
// Create a node with two revisions, the initial one belonging to the
|
||||
// cancelling user.
|
||||
$revision_node = $this->drupalCreateNode(['uid' => $account->id()]);
|
||||
$revision = $revision_node->getRevisionId();
|
||||
$settings = get_object_vars($revision_node);
|
||||
$settings['revision'] = 1;
|
||||
// Set new/current revision to someone else.
|
||||
$settings['uid'] = 1;
|
||||
$revision_node = $this->drupalCreateNode($settings);
|
||||
|
||||
// Attempt to cancel account.
|
||||
$this->drupalGet('user/' . $account->id() . '/edit');
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.');
|
||||
$this->assertText(t('Your account will be removed and all account information deleted. All of your content will also be deleted.'), 'Informs that all content will be deleted.');
|
||||
|
||||
// Confirm account cancellation.
|
||||
$timestamp = time();
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertText(t('A confirmation request to cancel your account has been sent to your email address.'), 'Account cancellation request mailed message displayed.');
|
||||
|
||||
// Confirm account cancellation request.
|
||||
$this->drupalGet("user/" . $account->id() . "/cancel/confirm/$timestamp/" . user_pass_rehash($account, $timestamp));
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$this->assertFalse($user_storage->load($account->id()), 'User is not found in the database.');
|
||||
|
||||
// Confirm that user's content has been deleted.
|
||||
$node_storage->resetCache([$node->id()]);
|
||||
$this->assertFalse($node_storage->load($node->id()), 'Node of the user has been deleted.');
|
||||
$this->assertFalse(node_revision_load($revision), 'Node revision of the user has been deleted.');
|
||||
$node_storage->resetCache([$revision_node->id()]);
|
||||
$this->assertTrue($node_storage->load($revision_node->id()), "Current revision of the user's node was not deleted.");
|
||||
\Drupal::entityManager()->getStorage('comment')->resetCache([$comment->id()]);
|
||||
$this->assertFalse(Comment::load($comment->id()), 'Comment of the user has been deleted.');
|
||||
|
||||
// Confirm that the confirmation message made it through to the end user.
|
||||
$this->assertRaw(t('%name has been deleted.', ['%name' => $account->getUsername()]), "Confirmation message displayed to user.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an administrative user and delete another user.
|
||||
*/
|
||||
public function testUserCancelByAdmin() {
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save();
|
||||
|
||||
// Create a regular user.
|
||||
$account = $this->drupalCreateUser([]);
|
||||
|
||||
// Create administrative user.
|
||||
$admin_user = $this->drupalCreateUser(['administer users']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Delete regular user.
|
||||
$this->drupalGet('user/' . $account->id() . '/edit');
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertRaw(t('Are you sure you want to cancel the account %name?', ['%name' => $account->getUsername()]), 'Confirmation form to cancel account displayed.');
|
||||
$this->assertText(t('Select the method to cancel the account above.'), 'Allows to select account cancellation method.');
|
||||
|
||||
// Confirm deletion.
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertRaw(t('%name has been deleted.', ['%name' => $account->getUsername()]), 'User deleted.');
|
||||
$this->assertFalse(User::load($account->id()), 'User is not found in the database.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests deletion of a user account without an email address.
|
||||
*/
|
||||
public function testUserWithoutEmailCancelByAdmin() {
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save();
|
||||
|
||||
// Create a regular user.
|
||||
$account = $this->drupalCreateUser([]);
|
||||
// This user has no email address.
|
||||
$account->mail = '';
|
||||
$account->save();
|
||||
|
||||
// Create administrative user.
|
||||
$admin_user = $this->drupalCreateUser(['administer users']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Delete regular user without email address.
|
||||
$this->drupalGet('user/' . $account->id() . '/edit');
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertRaw(t('Are you sure you want to cancel the account %name?', ['%name' => $account->getUsername()]), 'Confirmation form to cancel account displayed.');
|
||||
$this->assertText(t('Select the method to cancel the account above.'), 'Allows to select account cancellation method.');
|
||||
|
||||
// Confirm deletion.
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel account'));
|
||||
$this->assertRaw(t('%name has been deleted.', ['%name' => $account->getUsername()]), 'User deleted.');
|
||||
$this->assertFalse(User::load($account->id()), 'User is not found in the database.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an administrative user and mass-delete other users.
|
||||
*/
|
||||
public function testMassUserCancelByAdmin() {
|
||||
\Drupal::service('module_installer')->install(['views']);
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
$this->config('user.settings')->set('cancel_method', 'user_cancel_reassign')->save();
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
// Enable account cancellation notification.
|
||||
$this->config('user.settings')->set('notify.status_canceled', TRUE)->save();
|
||||
|
||||
// Create administrative user.
|
||||
$admin_user = $this->drupalCreateUser(['administer users']);
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create some users.
|
||||
$users = [];
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$account = $this->drupalCreateUser([]);
|
||||
$users[$account->id()] = $account;
|
||||
}
|
||||
|
||||
// Cancel user accounts, including own one.
|
||||
$edit = [];
|
||||
$edit['action'] = 'user_cancel_user_action';
|
||||
for ($i = 0; $i <= 4; $i++) {
|
||||
$edit['user_bulk_form[' . $i . ']'] = TRUE;
|
||||
}
|
||||
$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.');
|
||||
$this->assertText(t('Notify user when account is canceled'), 'Allows to send notification mail.');
|
||||
|
||||
// Confirm deletion.
|
||||
$this->drupalPostForm(NULL, NULL, t('Cancel accounts'));
|
||||
$status = TRUE;
|
||||
foreach ($users as $account) {
|
||||
$status = $status && (strpos($this->getTextContent(), $account->getUsername() . ' has been deleted.') !== FALSE);
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$status = $status && !$user_storage->load($account->id());
|
||||
}
|
||||
$this->assertTrue($status, 'Users deleted and not found in the database.');
|
||||
|
||||
// Ensure that admin account was not cancelled.
|
||||
$this->assertText(t('A confirmation request to cancel your account has been sent to your email address.'), 'Account cancellation request mailed message displayed.');
|
||||
$admin_user = $user_storage->load($admin_user->id());
|
||||
$this->assertTrue($admin_user->isActive(), 'Administrative user is found in the database and enabled.');
|
||||
|
||||
// Verify that uid 1's account was not cancelled.
|
||||
$user_storage->resetCache([1]);
|
||||
$user1 = $user_storage->load(1);
|
||||
$this->assertTrue($user1->isActive(), 'User #1 still exists and is not blocked.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user cancel with node access.
|
||||
*/
|
||||
public function testUserDeleteWithContentAndNodeAccess() {
|
||||
|
||||
\Drupal::service('module_installer')->install(['node_access_test']);
|
||||
// Rebuild node access.
|
||||
node_access_rebuild();
|
||||
|
||||
$account = $this->drupalCreateUser(['access content']);
|
||||
$node = $this->drupalCreateNode(['type' => 'page', 'uid' => $account->id()]);
|
||||
$account->delete();
|
||||
$load2 = \Drupal::entityTypeManager()->getStorage('node')->load($node->id());
|
||||
$this->assertTrue(empty($load2));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the create user administration page.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserCreateFailMailTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['system_mail_failure_test'];
|
||||
|
||||
/**
|
||||
* Tests the create user administration page.
|
||||
*/
|
||||
public function testUserAdd() {
|
||||
$user = $this->drupalCreateUser(['administer users']);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
// Replace the mail functionality with a fake, malfunctioning service.
|
||||
$this->config('system.mail')->set('interface.default', 'test_php_mail_failure')->save();
|
||||
// Create a user, but fail to send an email.
|
||||
$name = $this->randomMachineName();
|
||||
$edit = [
|
||||
'name' => $name,
|
||||
'mail' => $this->randomMachineName() . '@example.com',
|
||||
'pass[pass1]' => $pass = $this->randomString(),
|
||||
'pass[pass2]' => $pass,
|
||||
'notify' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm('admin/people/create', $edit, t('Create new account'));
|
||||
|
||||
$this->assertText(t('Unable to send email. Contact the site administrator if the problem persists.'));
|
||||
$this->assertNoText(t('A welcome message with further instructions has been emailed to the new user @name.', ['@name' => $edit['name']]));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Test\AssertMailTrait;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the create user administration page.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserCreateTest extends BrowserTestBase {
|
||||
|
||||
use AssertMailTrait {
|
||||
getMails as drupalGetMails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['image'];
|
||||
|
||||
/**
|
||||
* Create a user through the administration interface and ensure that it
|
||||
* displays in the user list.
|
||||
*/
|
||||
public function testUserAdd() {
|
||||
$user = $this->drupalCreateUser(['administer users']);
|
||||
$this->drupalLogin($user);
|
||||
|
||||
$this->assertEqual($user->getCreatedTime(), REQUEST_TIME, 'Creating a user sets default "created" timestamp.');
|
||||
$this->assertEqual($user->getChangedTime(), REQUEST_TIME, 'Creating a user sets default "changed" timestamp.');
|
||||
|
||||
// Create a field.
|
||||
$field_name = 'test_field';
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'user',
|
||||
'module' => 'image',
|
||||
'type' => 'image',
|
||||
'cardinality' => 1,
|
||||
'locked' => FALSE,
|
||||
'indexes' => ['target_id' => ['target_id']],
|
||||
'settings' => [
|
||||
'uri_scheme' => 'public',
|
||||
],
|
||||
])->save();
|
||||
|
||||
FieldConfig::create([
|
||||
'field_name' => $field_name,
|
||||
'entity_type' => 'user',
|
||||
'label' => 'Picture',
|
||||
'bundle' => 'user',
|
||||
'description' => t('Your virtual face or picture.'),
|
||||
'required' => FALSE,
|
||||
'settings' => [
|
||||
'file_extensions' => 'png gif jpg jpeg',
|
||||
'file_directory' => 'pictures',
|
||||
'max_filesize' => '30 KB',
|
||||
'alt_field' => 0,
|
||||
'title_field' => 0,
|
||||
'max_resolution' => '85x85',
|
||||
'min_resolution' => '',
|
||||
],
|
||||
])->save();
|
||||
|
||||
// Test user creation page for valid fields.
|
||||
$this->drupalGet('admin/people/create');
|
||||
$this->assertFieldbyId('edit-status-0', 0, 'The user status option Blocked exists.', 'User login');
|
||||
$this->assertFieldbyId('edit-status-1', 1, 'The user status option Active exists.', 'User login');
|
||||
$this->assertFieldByXPath('//input[@type="radio" and @id="edit-status-1" and @checked="checked"]', NULL, 'Default setting for user status is active.');
|
||||
|
||||
// Test that browser autocomplete behavior does not occur.
|
||||
$this->assertNoRaw('data-user-info-from-browser', 'Ensure form attribute, data-user-info-from-browser, does not exist.');
|
||||
|
||||
// Test that the password strength indicator displays.
|
||||
$config = $this->config('user.settings');
|
||||
|
||||
$config->set('password_strength', TRUE)->save();
|
||||
$this->drupalGet('admin/people/create');
|
||||
$this->assertRaw(t('Password strength:'), 'The password strength indicator is displayed.');
|
||||
|
||||
$config->set('password_strength', FALSE)->save();
|
||||
$this->drupalGet('admin/people/create');
|
||||
$this->assertNoRaw(t('Password strength:'), 'The password strength indicator is not displayed.');
|
||||
|
||||
// We create two users, notifying one and not notifying the other, to
|
||||
// ensure that the tests work in both cases.
|
||||
foreach ([FALSE, TRUE] as $notify) {
|
||||
$name = $this->randomMachineName();
|
||||
$edit = [
|
||||
'name' => $name,
|
||||
'mail' => $this->randomMachineName() . '@example.com',
|
||||
'pass[pass1]' => $pass = $this->randomString(),
|
||||
'pass[pass2]' => $pass,
|
||||
'notify' => $notify,
|
||||
];
|
||||
$this->drupalPostForm('admin/people/create', $edit, t('Create new account'));
|
||||
|
||||
if ($notify) {
|
||||
$this->assertText(t('A welcome message with further instructions has been emailed to the new user @name.', ['@name' => $edit['name']]), 'User created');
|
||||
$this->assertEqual(count($this->drupalGetMails()), 1, 'Notification email sent');
|
||||
}
|
||||
else {
|
||||
$this->assertText(t('Created a new user account for @name. No email has been sent.', ['@name' => $edit['name']]), 'User created');
|
||||
$this->assertEqual(count($this->drupalGetMails()), 0, 'Notification email not sent');
|
||||
}
|
||||
|
||||
$this->drupalGet('admin/people');
|
||||
$this->assertText($edit['name'], 'User found in list of users');
|
||||
$user = user_load_by_name($name);
|
||||
$this->assertTrue($user->isActive(), 'User is not blocked');
|
||||
}
|
||||
|
||||
// Test that the password '0' is considered a password.
|
||||
// @see https://www.drupal.org/node/2563751.
|
||||
$name = $this->randomMachineName();
|
||||
$edit = [
|
||||
'name' => $name,
|
||||
'mail' => $this->randomMachineName() . '@example.com',
|
||||
'pass[pass1]' => 0,
|
||||
'pass[pass2]' => 0,
|
||||
'notify' => FALSE,
|
||||
];
|
||||
$this->drupalPostForm('admin/people/create', $edit, t('Create new account'));
|
||||
$this->assertText("Created a new user account for $name. No email has been sent");
|
||||
$this->assertNoText('Password field is required');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Tests account deleting of users.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserDeleteTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Test deleting multiple users.
|
||||
*/
|
||||
public function testUserDeleteMultiple() {
|
||||
// Create a few users with permissions, so roles will be created.
|
||||
$user_a = $this->drupalCreateUser(['access user profiles']);
|
||||
$user_b = $this->drupalCreateUser(['access user profiles']);
|
||||
$user_c = $this->drupalCreateUser(['access user profiles']);
|
||||
|
||||
$uids = [$user_a->id(), $user_b->id(), $user_c->id()];
|
||||
|
||||
// These users should have a role
|
||||
$query = db_select('user__roles', 'r');
|
||||
$roles_created = $query
|
||||
->fields('r', ['entity_id'])
|
||||
->condition('entity_id', $uids, 'IN')
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
|
||||
$this->assertTrue($roles_created > 0, 'Role assignments created for new users and deletion of role assignments can be tested');
|
||||
// We should be able to load one of the users.
|
||||
$this->assertTrue(User::load($user_a->id()), 'User is created and deletion of user can be tested');
|
||||
// Delete the users.
|
||||
user_delete_multiple($uids);
|
||||
// Test if the roles assignments are deleted.
|
||||
$query = db_select('user__roles', 'r');
|
||||
$roles_after_deletion = $query
|
||||
->fields('r', ['entity_id'])
|
||||
->condition('entity_id', $uids, 'IN')
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
$this->assertTrue($roles_after_deletion == 0, 'Role assignments deleted along with users');
|
||||
// Test if the users are deleted, User::load() will return NULL.
|
||||
$this->assertNull(User::load($user_a->id()), format_string('User with id @uid deleted.', ['@uid' => $user_a->id()]));
|
||||
$this->assertNull(User::load($user_b->id()), format_string('User with id @uid deleted.', ['@uid' => $user_b->id()]));
|
||||
$this->assertNull(User::load($user_c->id()), format_string('User with id @uid deleted.', ['@uid' => $user_c->id()]));
|
||||
}
|
||||
|
||||
}
|
154
2017/web/core/modules/user/tests/src/Functional/UserEditTest.php
Normal file
154
2017/web/core/modules/user/tests/src/Functional/UserEditTest.php
Normal file
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests user edit page.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserEditTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* 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']);
|
||||
Cache::invalidateTags(['rendered']);
|
||||
$this->drupalGet('user/' . $user1->id() . '/edit');
|
||||
$this->assertFieldByName('name', $user1->getAccountName());
|
||||
|
||||
// Ensure the formatted name is displayed when expected.
|
||||
$this->drupalGet('user/' . $user1->id());
|
||||
$this->assertSession()->responseContains($user1->getDisplayName());
|
||||
$this->assertSession()->titleEquals(strip_tags($user1->getDisplayName()) . ' | Drupal');
|
||||
|
||||
// Check that filling out a single password field does not validate.
|
||||
$edit = [];
|
||||
$edit['pass[pass1]'] = '';
|
||||
$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->passRaw;
|
||||
$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->passRaw;
|
||||
$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->passRaw = $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."));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests user edited own account can still log in.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserEditedOwnAccountTest extends BrowserTestBase {
|
||||
|
||||
public function testUserEditedOwnAccount() {
|
||||
// Change account setting 'Who can register accounts?' to Administrators
|
||||
// only.
|
||||
$this->config('user.settings')->set('register', USER_REGISTER_ADMINISTRATORS_ONLY)->save();
|
||||
|
||||
// Create a new user account and log in.
|
||||
$account = $this->drupalCreateUser(['change own username']);
|
||||
$this->drupalLogin($account);
|
||||
|
||||
// Change own username.
|
||||
$edit = [];
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$this->drupalPostForm('user/' . $account->id() . '/edit', $edit, t('Save'));
|
||||
|
||||
// Log out.
|
||||
$this->drupalLogout();
|
||||
|
||||
// Set the new name on the user account and attempt to log back in.
|
||||
$account->name = $edit['name'];
|
||||
$this->drupalLogin($account);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Tests specific parts of the user entity like the URI callback and the label
|
||||
* callback.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserEntityCallbacksTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['user', 'user_hooks_test'];
|
||||
|
||||
/**
|
||||
* An authenticated user to use for testing.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* An anonymous user to use for testing.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $anonymous;
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->account = $this->drupalCreateUser();
|
||||
$this->anonymous = User::create(['uid' => 0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test label callback.
|
||||
*/
|
||||
public function testLabelCallback() {
|
||||
$this->assertEqual($this->account->label(), $this->account->getUsername(), 'The username should be used as label');
|
||||
|
||||
// Setup a random anonymous name to be sure the name is used.
|
||||
$name = $this->randomMachineName();
|
||||
$this->config('user.settings')->set('anonymous', $name)->save();
|
||||
$this->assertEqual($this->anonymous->label(), $name, 'The variable anonymous should be used for name of uid 0');
|
||||
$this->assertEqual($this->anonymous->getDisplayName(), $name, 'The variable anonymous should be used for display name of uid 0');
|
||||
$this->assertEqual($this->anonymous->getUserName(), '', 'The raw anonymous user name should be empty string');
|
||||
|
||||
// Set to test the altered username.
|
||||
\Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE);
|
||||
|
||||
$this->assertEqual($this->account->getDisplayName(), '<em>' . $this->account->id() . '</em>', 'The user display name should be altered.');
|
||||
$this->assertEqual($this->account->getUsername(), $this->account->name->value, 'The user name should not be altered.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests whether proper language is stored for new users and access to language
|
||||
* selector.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserLanguageCreationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* 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 passRaw so we can log in the new user.
|
||||
$user->passRaw = $this->randomMachineName(10);
|
||||
$edit = [
|
||||
'pass[pass1]' => $user->passRaw,
|
||||
'pass[pass2]' => $user->passRaw,
|
||||
];
|
||||
|
||||
$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.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Functional tests for a user's ability to change their default language.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserLanguageTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['user', 'language'];
|
||||
|
||||
/**
|
||||
* Test if user can change their default language.
|
||||
*/
|
||||
public function testUserLanguageConfiguration() {
|
||||
// User to add and remove language.
|
||||
$admin_user = $this->drupalCreateUser(['administer languages', 'access administration pages']);
|
||||
// User to change their default language.
|
||||
$web_user = $this->drupalCreateUser();
|
||||
|
||||
// Add custom language.
|
||||
$this->drupalLogin($admin_user);
|
||||
// Code for the language.
|
||||
$langcode = 'xx';
|
||||
// The English name for the language.
|
||||
$name = $this->randomMachineName(16);
|
||||
$edit = [
|
||||
'predefined_langcode' => 'custom',
|
||||
'langcode' => $langcode,
|
||||
'label' => $name,
|
||||
'direction' => LanguageInterface::DIRECTION_LTR,
|
||||
];
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
|
||||
$this->drupalLogout();
|
||||
|
||||
// Log in as normal user and edit account settings.
|
||||
$this->drupalLogin($web_user);
|
||||
$path = 'user/' . $web_user->id() . '/edit';
|
||||
$this->drupalGet($path);
|
||||
// Ensure language settings widget is available.
|
||||
$this->assertText(t('Language'), 'Language selector available.');
|
||||
// Ensure custom language is present.
|
||||
$this->assertText($name, 'Language present on form.');
|
||||
// Switch to our custom language.
|
||||
$edit = [
|
||||
'preferred_langcode' => $langcode,
|
||||
];
|
||||
$this->drupalPostForm($path, $edit, t('Save'));
|
||||
// Ensure form was submitted successfully.
|
||||
$this->assertText(t('The changes have been saved.'), 'Changes were saved.');
|
||||
// Check if language was changed.
|
||||
$this->assertOptionSelected('edit-preferred-langcode', $langcode, 'Default language successfully updated.');
|
||||
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,544 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Flood\DatabaseBackend;
|
||||
use Drupal\Core\Test\AssertMailTrait;
|
||||
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 Drupal\hal\Encoder\JsonEncoder as HALJsonEncoder;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
|
||||
/**
|
||||
* Tests login and password reset via direct HTTP.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserLoginHttpTest extends BrowserTestBase {
|
||||
|
||||
use AssertMailTrait {
|
||||
getMails as drupalGetMails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['hal'];
|
||||
|
||||
/**
|
||||
* 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(), new HALJsonEncoder()];
|
||||
$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.
|
||||
*/
|
||||
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() {
|
||||
// Without the serialization module only JSON is supported.
|
||||
$this->doTestLogin('json');
|
||||
|
||||
// Enable serialization so we have access to additional formats.
|
||||
$this->container->get('module_installer')->install(['serialization']);
|
||||
$this->doTestLogin('json');
|
||||
$this->doTestLogin('xml');
|
||||
$this->doTestLogin('hal_json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Do login testing for a given serialization format.
|
||||
*
|
||||
* @param string $format
|
||||
* Serialization format.
|
||||
*/
|
||||
protected function doTestLogin($format) {
|
||||
$client = \Drupal::httpClient();
|
||||
// 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'];
|
||||
|
||||
// Logging in while already logged in results in a 403 with helpful message.
|
||||
$response = $this->loginRequest($name, $pass, $format);
|
||||
$this->assertSame(403, $response->getStatusCode());
|
||||
$this->assertSame(['message' => 'This route can only be accessed by anonymous users.'], $this->serializer->decode($response->getBody(), $format));
|
||||
|
||||
$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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a password HTTP request.
|
||||
*
|
||||
* @param array $request_body
|
||||
* The request body.
|
||||
* @param string $format
|
||||
* The format to use to make the request.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
* The HTTP response.
|
||||
*/
|
||||
protected function passwordRequest(array $request_body, $format = 'json') {
|
||||
$password_reset_url = Url::fromRoute('user.pass.http')
|
||||
->setRouteParameter('_format', $format)
|
||||
->setAbsolute();
|
||||
|
||||
$result = \Drupal::httpClient()->post($password_reset_url->toString(), [
|
||||
'body' => $this->serializer->encode($request_body, $format),
|
||||
'headers' => [
|
||||
'Accept' => "application/$format",
|
||||
],
|
||||
'http_errors' => FALSE,
|
||||
'cookies' => $this->cookies,
|
||||
]);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests user password reset.
|
||||
*/
|
||||
public function testPasswordReset() {
|
||||
// Create a user account.
|
||||
$account = $this->drupalCreateUser();
|
||||
|
||||
// Without the serialization module only JSON is supported.
|
||||
$this->doTestPasswordReset('json', $account);
|
||||
|
||||
// Enable serialization so we have access to additional formats.
|
||||
$this->container->get('module_installer')->install(['serialization']);
|
||||
|
||||
$this->doTestPasswordReset('json', $account);
|
||||
$this->doTestPasswordReset('xml', $account);
|
||||
$this->doTestPasswordReset('hal_json', $account);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do password reset testing for given format and account.
|
||||
*
|
||||
* @param string $format
|
||||
* Serialization format.
|
||||
* @param \Drupal\user\UserInterface $account
|
||||
* Test account.
|
||||
*/
|
||||
protected function doTestPasswordReset($format, $account) {
|
||||
$response = $this->passwordRequest([], $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Missing credentials.name or credentials.mail', $format);
|
||||
|
||||
$response = $this->passwordRequest(['name' => 'dramallama'], $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Unrecognized username or email address.', $format);
|
||||
|
||||
$response = $this->passwordRequest(['mail' => 'llama@drupal.org'], $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'Unrecognized username or email address.', $format);
|
||||
|
||||
$account
|
||||
->block()
|
||||
->save();
|
||||
|
||||
$response = $this->passwordRequest(['name' => $account->getAccountName()], $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'The user has not been activated or is blocked.', $format);
|
||||
|
||||
$response = $this->passwordRequest(['mail' => $account->getEmail()], $format);
|
||||
$this->assertHttpResponseWithMessage($response, 400, 'The user has not been activated or is blocked.', $format);
|
||||
|
||||
$account
|
||||
->activate()
|
||||
->save();
|
||||
|
||||
$response = $this->passwordRequest(['name' => $account->getAccountName()], $format);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->loginFromResetEmail();
|
||||
$this->drupalLogout();
|
||||
|
||||
$response = $this->passwordRequest(['mail' => $account->getEmail()], $format);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
$this->loginFromResetEmail();
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Login from reset password email.
|
||||
*/
|
||||
protected function loginFromResetEmail() {
|
||||
$_emails = $this->drupalGetMails();
|
||||
$email = end($_emails);
|
||||
$urls = [];
|
||||
preg_match('#.+user/reset/.+#', $email['body'], $urls);
|
||||
$resetURL = $urls[0];
|
||||
$this->drupalGet($resetURL);
|
||||
$this->drupalPostForm(NULL, NULL, 'Log in');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Ensure that login works as expected.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserLoginTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* 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->passRaw];
|
||||
$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->passRaw .= '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->passRaw .= '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->passRaw;
|
||||
$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->passRaw = $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 passRaw 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->passRaw,
|
||||
];
|
||||
$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?'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Test\AssertMailTrait;
|
||||
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests _user_mail_notify() use of user.settings.notify.*.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserMailNotifyTest extends EntityKernelTestBase {
|
||||
|
||||
use AssertMailTrait {
|
||||
getMails as drupalGetMails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for user mail testing.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function userMailsProvider() {
|
||||
return [
|
||||
['cancel_confirm', ['cancel_confirm']],
|
||||
['password_reset', ['password_reset']],
|
||||
['status_activated', ['status_activated']],
|
||||
['status_blocked', ['status_blocked']],
|
||||
['status_canceled', ['status_canceled']],
|
||||
['register_admin_created', ['register_admin_created']],
|
||||
['register_no_approval_required', ['register_no_approval_required']],
|
||||
['register_pending_approval', ['register_pending_approval', 'register_pending_approval_admin']],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests mails are sent when notify.$op is TRUE.
|
||||
*
|
||||
* @param string $op
|
||||
* The operation being performed on the account.
|
||||
* @param array $mail_keys
|
||||
* The mail keys to test for.
|
||||
*
|
||||
* @dataProvider userMailsProvider
|
||||
*/
|
||||
public function testUserMailsSent($op, array $mail_keys) {
|
||||
$this->config('user.settings')->set('notify.' . $op, TRUE)->save();
|
||||
$return = _user_mail_notify($op, $this->createUser());
|
||||
$this->assertTrue($return, '_user_mail_notify() returns TRUE.');
|
||||
foreach ($mail_keys as $key) {
|
||||
$filter = ['key' => $key];
|
||||
$this->assertNotEmpty($this->getMails($filter), "Mails with $key exists.");
|
||||
}
|
||||
$this->assertCount(count($mail_keys), $this->getMails(), 'The expected number of emails sent.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests mails are not sent when notify.$op is FALSE.
|
||||
*
|
||||
* @param string $op
|
||||
* The operation being performed on the account.
|
||||
* @param array $mail_keys
|
||||
* The mail keys to test for. Ignored by this test because we assert that no
|
||||
* mails at all are sent.
|
||||
*
|
||||
* @dataProvider userMailsProvider
|
||||
*/
|
||||
public function testUserMailsNotSent($op, array $mail_keys) {
|
||||
$this->config('user.settings')->set('notify.' . $op, FALSE)->save();
|
||||
$return = _user_mail_notify($op, $this->createUser());
|
||||
$this->assertFalse($return, '_user_mail_notify() returns FALSE.');
|
||||
$this->assertEmpty($this->getMails(), 'No emails sent by _user_mail_notify().');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,326 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\Test\AssertMailTrait;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\system\Functional\Cache\PageCacheTagsTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Ensure that password reset methods work as expected.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserPasswordResetTest extends PageCacheTagsTestBase {
|
||||
|
||||
use AssertMailTrait {
|
||||
getMails as drupalGetMails;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user object to test password resetting.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['block'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalPlaceBlock('system_menu_block:account');
|
||||
|
||||
// Create a user.
|
||||
$account = $this->drupalCreateUser();
|
||||
|
||||
// Activate user by logging in.
|
||||
$this->drupalLogin($account);
|
||||
|
||||
$this->account = User::load($account->id());
|
||||
$this->account->passRaw = $account->passRaw;
|
||||
$this->drupalLogout();
|
||||
|
||||
// Set the last login time that is used to generate the one-time link so
|
||||
// that it is definitely over a second ago.
|
||||
$account->login = REQUEST_TIME - mt_rand(10, 100000);
|
||||
db_update('users_field_data')
|
||||
->fields(['login' => $account->getLastLoginTime()])
|
||||
->condition('uid', $account->id())
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests password reset functionality.
|
||||
*/
|
||||
public function testUserPasswordReset() {
|
||||
// Verify that accessing the password reset form without having the session
|
||||
// variables set results in an access denied message.
|
||||
$this->drupalGet(Url::fromRoute('user.reset.form', ['uid' => $this->account->id()]));
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Try to reset the password for an invalid account.
|
||||
$this->drupalGet('user/password');
|
||||
|
||||
$edit = ['name' => $this->randomMachineName(32)];
|
||||
$this->drupalPostForm(NULL, $edit, t('Submit'));
|
||||
|
||||
$this->assertText(t('@name is not recognized as a username or an email address.', ['@name' => $edit['name']]), 'Validation error message shown when trying to request password for invalid account.');
|
||||
$this->assertEqual(count($this->drupalGetMails(['id' => 'user_password_reset'])), 0, 'No email was sent when requesting a password for an invalid account.');
|
||||
|
||||
// Reset the password by username via the password reset page.
|
||||
$edit['name'] = $this->account->getUsername();
|
||||
$this->drupalPostForm(NULL, $edit, t('Submit'));
|
||||
|
||||
// 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', ['@username' => $this->account->getUsername(), '@site' => $this->config('system.site')->get('name')]);
|
||||
$this->assertMail('subject', $subject, 'Password reset email subject is correct.');
|
||||
|
||||
$resetURL = $this->getResetURL();
|
||||
$this->drupalGet($resetURL);
|
||||
// Ensure that the current url does not contain the hash and timestamp.
|
||||
$this->assertUrl(Url::fromRoute('user.reset.form', ['uid' => $this->account->id()]));
|
||||
|
||||
$this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'));
|
||||
|
||||
// Ensure the password reset URL is not cached.
|
||||
$this->drupalGet($resetURL);
|
||||
$this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'));
|
||||
|
||||
// Check the one-time login page.
|
||||
$this->assertText($this->account->getUsername(), 'One-time login page contains the correct username.');
|
||||
$this->assertText(t('This login can be used only once.'), 'Found warning about one-time login.');
|
||||
$this->assertTitle(t('Reset password | Drupal'), 'Page title is "Reset password".');
|
||||
|
||||
// Check successful login.
|
||||
$this->drupalPostForm(NULL, NULL, t('Log in'));
|
||||
$this->assertLink(t('Log out'));
|
||||
$this->assertTitle(t('@name | @site', ['@name' => $this->account->getUsername(), '@site' => $this->config('system.site')->get('name')]), 'Logged in using password reset link.');
|
||||
|
||||
// Change the forgotten password.
|
||||
$password = user_password();
|
||||
$edit = ['pass[pass1]' => $password, 'pass[pass2]' => $password];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertText(t('The changes have been saved.'), 'Forgotten password changed.');
|
||||
|
||||
// Verify that the password reset session has been destroyed.
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertText(t("Your current password is missing or incorrect; it's required to change the Password."), 'Password needed to make profile changes.');
|
||||
|
||||
// Log out, and try to log in again using the same one-time link.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet($resetURL);
|
||||
$this->drupalPostForm(NULL, NULL, t('Log in'));
|
||||
$this->assertText(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'), 'One-time link is no longer valid.');
|
||||
|
||||
// Request a new password again, this time using the email address.
|
||||
$this->drupalGet('user/password');
|
||||
// Count email messages before to compare with after.
|
||||
$before = count($this->drupalGetMails(['id' => 'user_password_reset']));
|
||||
$edit = ['name' => $this->account->getEmail()];
|
||||
$this->drupalPostForm(NULL, $edit, t('Submit'));
|
||||
$this->assertTrue(count($this->drupalGetMails(['id' => 'user_password_reset'])) === $before + 1, 'Email sent when requesting password reset using email address.');
|
||||
|
||||
// Visit the user edit page without pass-reset-token and make sure it does
|
||||
// not cause an error.
|
||||
$resetURL = $this->getResetURL();
|
||||
$this->drupalGet($resetURL);
|
||||
$this->drupalPostForm(NULL, NULL, t('Log in'));
|
||||
$this->drupalGet('user/' . $this->account->id() . '/edit');
|
||||
$this->assertNoText('Expected user_string to be a string, NULL given');
|
||||
$this->drupalLogout();
|
||||
|
||||
// Create a password reset link as if the request time was 60 seconds older than the allowed limit.
|
||||
$timeout = $this->config('user.settings')->get('password_reset_timeout');
|
||||
$bogus_timestamp = REQUEST_TIME - $timeout - 60;
|
||||
$_uid = $this->account->id();
|
||||
$this->drupalGet("user/reset/$_uid/$bogus_timestamp/" . user_pass_rehash($this->account, $bogus_timestamp));
|
||||
$this->drupalPostForm(NULL, NULL, t('Log in'));
|
||||
$this->assertText(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'Expired password reset request rejected.');
|
||||
|
||||
// Create a user, block the account, and verify that a login link is denied.
|
||||
$timestamp = REQUEST_TIME - 1;
|
||||
$blocked_account = $this->drupalCreateUser()->block();
|
||||
$blocked_account->save();
|
||||
$this->drupalGet("user/reset/" . $blocked_account->id() . "/$timestamp/" . user_pass_rehash($blocked_account, $timestamp));
|
||||
$this->assertResponse(403);
|
||||
|
||||
// Verify a blocked user can not request a new password.
|
||||
$this->drupalGet('user/password');
|
||||
// Count email messages before to compare with after.
|
||||
$before = count($this->drupalGetMails(['id' => 'user_password_reset']));
|
||||
$edit = ['name' => $blocked_account->getUsername()];
|
||||
$this->drupalPostForm(NULL, $edit, t('Submit'));
|
||||
$this->assertRaw(t('%name is blocked or has not been activated yet.', ['%name' => $blocked_account->getUsername()]), 'Notified user blocked accounts can not request a new password');
|
||||
$this->assertTrue(count($this->drupalGetMails(['id' => 'user_password_reset'])) === $before, 'No email was sent when requesting password reset for a blocked account');
|
||||
|
||||
// Verify a password reset link is invalidated when the user's email address changes.
|
||||
$this->drupalGet('user/password');
|
||||
$edit = ['name' => $this->account->getUsername()];
|
||||
$this->drupalPostForm(NULL, $edit, t('Submit'));
|
||||
$old_email_reset_link = $this->getResetURL();
|
||||
$this->account->setEmail("1" . $this->account->getEmail());
|
||||
$this->account->save();
|
||||
$this->drupalGet($old_email_reset_link);
|
||||
$this->drupalPostForm(NULL, NULL, t('Log in'));
|
||||
$this->assertText(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'), 'One-time link is no longer valid.');
|
||||
|
||||
// Verify a password reset link will automatically log a user when /login is
|
||||
// appended.
|
||||
$this->drupalGet('user/password');
|
||||
$edit = ['name' => $this->account->getUsername()];
|
||||
$this->drupalPostForm(NULL, $edit, t('Submit'));
|
||||
$reset_url = $this->getResetURL();
|
||||
$this->drupalGet($reset_url . '/login');
|
||||
$this->assertLink(t('Log out'));
|
||||
$this->assertTitle(t('@name | @site', ['@name' => $this->account->getUsername(), '@site' => $this->config('system.site')->get('name')]), 'Logged in using password reset link.');
|
||||
|
||||
// Ensure blocked and deleted accounts can't access the user.reset.login
|
||||
// route.
|
||||
$this->drupalLogout();
|
||||
$timestamp = REQUEST_TIME - 1;
|
||||
$blocked_account = $this->drupalCreateUser()->block();
|
||||
$blocked_account->save();
|
||||
$this->drupalGet("user/reset/" . $blocked_account->id() . "/$timestamp/" . user_pass_rehash($blocked_account, $timestamp) . '/login');
|
||||
$this->assertResponse(403);
|
||||
|
||||
$blocked_account->delete();
|
||||
$this->drupalGet("user/reset/" . $blocked_account->id() . "/$timestamp/" . user_pass_rehash($blocked_account, $timestamp) . '/login');
|
||||
$this->assertResponse(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves password reset email and extracts the login link.
|
||||
*/
|
||||
public function getResetURL() {
|
||||
// Assume the most recent email.
|
||||
$_emails = $this->drupalGetMails();
|
||||
$email = end($_emails);
|
||||
$urls = [];
|
||||
preg_match('#.+user/reset/.+#', $email['body'], $urls);
|
||||
|
||||
return $urls[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user password reset while logged in.
|
||||
*/
|
||||
public function testUserPasswordResetLoggedIn() {
|
||||
$another_account = $this->drupalCreateUser();
|
||||
$this->drupalLogin($another_account);
|
||||
$this->drupalGet('user/password');
|
||||
$this->drupalPostForm(NULL, NULL, t('Submit'));
|
||||
|
||||
// Click the reset URL while logged and change our password.
|
||||
$resetURL = $this->getResetURL();
|
||||
// Log in as a different user.
|
||||
$this->drupalLogin($this->account);
|
||||
$this->drupalGet($resetURL);
|
||||
$this->assertRaw(new FormattableMarkup(
|
||||
'Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please <a href=":logout">log out</a> and try using the link again.',
|
||||
['%other_user' => $this->account->getUsername(), '%resetting_user' => $another_account->getUsername(), ':logout' => Url::fromRoute('user.logout')->toString()]
|
||||
));
|
||||
|
||||
$another_account->delete();
|
||||
$this->drupalGet($resetURL);
|
||||
$this->assertText('The one-time login link you clicked is invalid.');
|
||||
|
||||
// Log in.
|
||||
$this->drupalLogin($this->account);
|
||||
|
||||
// Reset the password by username via the password reset page.
|
||||
$this->drupalGet('user/password');
|
||||
$this->drupalPostForm(NULL, NULL, t('Submit'));
|
||||
|
||||
// Click the reset URL while logged and change our password.
|
||||
$resetURL = $this->getResetURL();
|
||||
$this->drupalGet($resetURL);
|
||||
$this->drupalPostForm(NULL, NULL, t('Log in'));
|
||||
|
||||
// Change the password.
|
||||
$password = user_password();
|
||||
$edit = ['pass[pass1]' => $password, 'pass[pass2]' => $password];
|
||||
$this->drupalPostForm(NULL, $edit, t('Save'));
|
||||
$this->assertText(t('The changes have been saved.'), 'Password changed.');
|
||||
|
||||
// Logged in users should not be able to access the user.reset.login or the
|
||||
// user.reset.form routes.
|
||||
$timestamp = REQUEST_TIME - 1;
|
||||
$this->drupalGet("user/reset/" . $this->account->id() . "/$timestamp/" . user_pass_rehash($this->account, $timestamp) . '/login');
|
||||
$this->assertResponse(403);
|
||||
$this->drupalGet("user/reset/" . $this->account->id());
|
||||
$this->assertResponse(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefill the text box on incorrect login via link to password reset page.
|
||||
*/
|
||||
public function testUserResetPasswordTextboxFilled() {
|
||||
$this->drupalGet('user/login');
|
||||
$edit = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'pass' => $this->randomMachineName(),
|
||||
];
|
||||
$this->drupalPostForm('user/login', $edit, t('Log in'));
|
||||
$this->assertRaw(t('Unrecognized username or password. <a href=":password">Forgot your password?</a>',
|
||||
[':password' => \Drupal::url('user.pass', [], ['query' => ['name' => $edit['name']]])]));
|
||||
unset($edit['pass']);
|
||||
$this->drupalGet('user/password', ['query' => ['name' => $edit['name']]]);
|
||||
$this->assertFieldByName('name', $edit['name'], 'User name found.');
|
||||
// Ensure the name field value is not cached.
|
||||
$this->drupalGet('user/password');
|
||||
$this->assertNoFieldByName('name', $edit['name'], 'User name not found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that users cannot forge password reset URLs of other users.
|
||||
*/
|
||||
public function testResetImpersonation() {
|
||||
// Create two identical user accounts except for the user name. They must
|
||||
// have the same empty password, so we can't use $this->drupalCreateUser().
|
||||
$edit = [];
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$edit['mail'] = $edit['name'] . '@example.com';
|
||||
$edit['status'] = 1;
|
||||
$user1 = User::create($edit);
|
||||
$user1->save();
|
||||
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$user2 = User::create($edit);
|
||||
$user2->save();
|
||||
|
||||
// Unique password hashes are automatically generated, the only way to
|
||||
// change that is to update it directly in the database.
|
||||
db_update('users_field_data')
|
||||
->fields(['pass' => NULL])
|
||||
->condition('uid', [$user1->id(), $user2->id()], 'IN')
|
||||
->execute();
|
||||
\Drupal::entityManager()->getStorage('user')->resetCache();
|
||||
$user1 = User::load($user1->id());
|
||||
$user2 = User::load($user2->id());
|
||||
|
||||
$this->assertEqual($user1->getPassword(), $user2->getPassword(), 'Both users have the same password hash.');
|
||||
|
||||
// The password reset URL must not be valid for the second user when only
|
||||
// the user ID is changed in the URL.
|
||||
$reset_url = user_pass_reset_url($user1);
|
||||
$attack_reset_url = str_replace("user/reset/{$user1->id()}", "user/reset/{$user2->id()}", $reset_url);
|
||||
$this->drupalGet($attack_reset_url);
|
||||
$this->drupalPostForm(NULL, NULL, t('Log in'));
|
||||
$this->assertNoText($user2->getUsername(), 'The invalid password reset page does not show the user name.');
|
||||
$this->assertUrl('user/password', [], '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.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
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 BrowserTestBase {
|
||||
|
||||
/**
|
||||
* 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->assertSession()->checkboxChecked('administrator[' . $permission . ']');
|
||||
$this->assertSession()->fieldDisabled('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.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify 'access content' is listed in the correct location.
|
||||
*/
|
||||
public function testAccessContentPermission() {
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// When Node is not installed the 'access content' permission is listed next
|
||||
// to 'access site reports'.
|
||||
$this->drupalGet('admin/people/permissions');
|
||||
$next_row = $this->xpath('//tr[@data-drupal-selector=\'edit-permissions-access-content\']/following-sibling::tr[1]');
|
||||
$this->assertEqual('edit-permissions-access-site-reports', $next_row[0]->getAttribute('data-drupal-selector'));
|
||||
|
||||
// When Node is installed the 'access content' permission is listed next to
|
||||
// to 'view own unpublished content'.
|
||||
\Drupal::service('module_installer')->install(['node']);
|
||||
$this->drupalGet('admin/people/permissions');
|
||||
$next_row = $this->xpath('//tr[@data-drupal-selector=\'edit-permissions-access-content\']/following-sibling::tr[1]');
|
||||
$this->assertEqual('edit-permissions-view-own-unpublished-content', $next_row[0]->getAttribute('data-drupal-selector'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\Tests\TestFileCreationTrait;
|
||||
|
||||
/**
|
||||
* Tests user picture functionality.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserPictureTest extends BrowserTestBase {
|
||||
|
||||
use TestFileCreationTrait {
|
||||
getTestFiles as drupalGetTestFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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::service('file_system')->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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,384 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests registration of user under different configurations.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserRegistrationTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['field_test'];
|
||||
|
||||
public function testRegistrationWithEmailVerification() {
|
||||
$config = $this->config('user.settings');
|
||||
// Require email verification.
|
||||
$config->set('verify_mail', TRUE)->save();
|
||||
|
||||
// Set registration to administrator only.
|
||||
$config->set('register', USER_REGISTER_ADMINISTRATORS_ONLY)->save();
|
||||
$this->drupalGet('user/register');
|
||||
$this->assertResponse(403, 'Registration page is inaccessible when only administrators can create accounts.');
|
||||
|
||||
// Allow registration by site visitors without administrator approval.
|
||||
$config->set('register', USER_REGISTER_VISITORS)->save();
|
||||
$edit = [];
|
||||
$edit['name'] = $name = $this->randomMachineName();
|
||||
$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.');
|
||||
|
||||
/** @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);
|
||||
$this->drupalGet($resetURL);
|
||||
$this->assertTitle(t('Set password | Drupal'), 'Page title is "Set password".');
|
||||
|
||||
// Allow registration by site visitors, but require administrator approval.
|
||||
$config->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
|
||||
$edit = [];
|
||||
$edit['name'] = $name = $this->randomMachineName();
|
||||
$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 = $storage->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertFalse($new_user->isActive(), 'New account is blocked until approved by an administrator.');
|
||||
}
|
||||
|
||||
public function testRegistrationWithoutEmailVerification() {
|
||||
$config = $this->config('user.settings');
|
||||
// Don't require email verification and allow registration by site visitors
|
||||
// without administrator approval.
|
||||
$config
|
||||
->set('verify_mail', FALSE)
|
||||
->set('register', USER_REGISTER_VISITORS)
|
||||
->save();
|
||||
|
||||
$edit = [];
|
||||
$edit['name'] = $name = $this->randomMachineName();
|
||||
$edit['mail'] = $mail = $edit['name'] . '@example.com';
|
||||
|
||||
// Try entering a mismatching password.
|
||||
$edit['pass[pass1]'] = '99999.0';
|
||||
$edit['pass[pass2]'] = '99999';
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->assertText(t('The specified passwords do not match.'), 'Typing mismatched passwords displays an error message.');
|
||||
|
||||
// Enter a correct password.
|
||||
$edit['pass[pass1]'] = $new_pass = $this->randomMachineName();
|
||||
$edit['pass[pass2]'] = $new_pass;
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->container->get('entity.manager')->getStorage('user')->resetCache();
|
||||
$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.');
|
||||
$this->drupalLogout();
|
||||
|
||||
// Allow registration by site visitors, but require administrator approval.
|
||||
$config->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
|
||||
$edit = [];
|
||||
$edit['name'] = $name = $this->randomMachineName();
|
||||
$edit['mail'] = $mail = $edit['name'] . '@example.com';
|
||||
$edit['pass[pass1]'] = $pass = $this->randomMachineName();
|
||||
$edit['pass[pass2]'] = $pass;
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->assertText(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.'), 'Users are notified of pending approval');
|
||||
|
||||
// Try to log in before administrator approval.
|
||||
$auth = [
|
||||
'name' => $name,
|
||||
'pass' => $pass,
|
||||
];
|
||||
$this->drupalPostForm('user/login', $auth, t('Log in'));
|
||||
$this->assertText(t('The username @name has not been activated or is blocked.', ['@name' => $name]), 'User cannot log in yet.');
|
||||
|
||||
// Activate the new account.
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$admin_user = $this->drupalCreateUser(['administer users']);
|
||||
$this->drupalLogin($admin_user);
|
||||
$edit = [
|
||||
'status' => 1,
|
||||
];
|
||||
$this->drupalPostForm('user/' . $new_user->id() . '/edit', $edit, t('Save'));
|
||||
$this->drupalLogout();
|
||||
|
||||
// Log in after administrator approval.
|
||||
$this->drupalPostForm('user/login', $auth, t('Log in'));
|
||||
$this->assertText(t('Member for'), 'User can log in after administrator approval.');
|
||||
}
|
||||
|
||||
public function testRegistrationEmailDuplicates() {
|
||||
// Don't require email verification and allow registration by site visitors
|
||||
// without administrator approval.
|
||||
$this->config('user.settings')
|
||||
->set('verify_mail', FALSE)
|
||||
->set('register', USER_REGISTER_VISITORS)
|
||||
->save();
|
||||
|
||||
// Set up a user to check for duplicates.
|
||||
$duplicate_user = $this->drupalCreateUser();
|
||||
|
||||
$edit = [];
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$edit['mail'] = $duplicate_user->getEmail();
|
||||
|
||||
// Attempt to create a new account using an existing email address.
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->assertText(t('The email address @email is already taken.', ['@email' => $duplicate_user->getEmail()]), 'Supplying an exact duplicate email address displays an error message');
|
||||
|
||||
// Attempt to bypass duplicate email registration validation by adding spaces.
|
||||
$edit['mail'] = ' ' . $duplicate_user->getEmail() . ' ';
|
||||
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->assertText(t('The email address @email is already taken.', ['@email' => $duplicate_user->getEmail()]), 'Supplying a duplicate email address with added whitespace displays an error message');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that UUID isn't cached in form state on register form.
|
||||
*
|
||||
* This is a regression test for https://www.drupal.org/node/2500527 to ensure
|
||||
* that the form is not cached on GET requests.
|
||||
*/
|
||||
public function testUuidFormState() {
|
||||
\Drupal::service('module_installer')->install(['image']);
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
|
||||
// Add a picture field in order to ensure that no form cache is written,
|
||||
// which breaks registration of more than 1 user every 6 hours.
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => 'user_picture',
|
||||
'entity_type' => 'user',
|
||||
'type' => 'image',
|
||||
]);
|
||||
$field_storage->save();
|
||||
|
||||
$field = FieldConfig::create([
|
||||
'field_name' => 'user_picture',
|
||||
'entity_type' => 'user',
|
||||
'bundle' => 'user',
|
||||
]);
|
||||
$field->save();
|
||||
|
||||
$form_display = EntityFormDisplay::create([
|
||||
'targetEntityType' => 'user',
|
||||
'bundle' => 'user',
|
||||
'mode' => 'default',
|
||||
'status' => TRUE,
|
||||
]);
|
||||
$form_display->setComponent('user_picture', [
|
||||
'type' => 'image_image',
|
||||
]);
|
||||
$form_display->save();
|
||||
|
||||
// Don't require email verification and allow registration by site visitors
|
||||
// without administrator approval.
|
||||
$this->config('user.settings')
|
||||
->set('verify_mail', FALSE)
|
||||
->set('register', USER_REGISTER_VISITORS)
|
||||
->save();
|
||||
|
||||
$edit = [];
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$edit['mail'] = $edit['name'] . '@example.com';
|
||||
$edit['pass[pass2]'] = $edit['pass[pass1]'] = $this->randomMachineName();
|
||||
|
||||
// Create one account.
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->assertResponse(200);
|
||||
|
||||
$user_storage = \Drupal::entityManager()->getStorage('user');
|
||||
|
||||
$this->assertTrue($user_storage->loadByProperties(['name' => $edit['name']]));
|
||||
$this->drupalLogout();
|
||||
|
||||
// Create a second account.
|
||||
$edit['name'] = $this->randomMachineName();
|
||||
$edit['mail'] = $edit['name'] . '@example.com';
|
||||
$edit['pass[pass2]'] = $edit['pass[pass1]'] = $this->randomMachineName();
|
||||
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->assertResponse(200);
|
||||
|
||||
$this->assertTrue($user_storage->loadByProperties(['name' => $edit['name']]));
|
||||
}
|
||||
|
||||
public function testRegistrationDefaultValues() {
|
||||
// Don't require email verification and allow registration by site visitors
|
||||
// without administrator approval.
|
||||
$config_user_settings = $this->config('user.settings')
|
||||
->set('verify_mail', FALSE)
|
||||
->set('register', USER_REGISTER_VISITORS)
|
||||
->save();
|
||||
|
||||
// Set the default timezone to Brussels.
|
||||
$config_system_date = $this->config('system.date')
|
||||
->set('timezone.user.configurable', 1)
|
||||
->set('timezone.default', 'Europe/Brussels')
|
||||
->save();
|
||||
|
||||
// Check the presence of expected cache tags.
|
||||
$this->drupalGet('user/register');
|
||||
$this->assertCacheTag('config:user.settings');
|
||||
|
||||
$edit = [];
|
||||
$edit['name'] = $name = $this->randomMachineName();
|
||||
$edit['mail'] = $mail = $edit['name'] . '@example.com';
|
||||
$edit['pass[pass1]'] = $new_pass = $this->randomMachineName();
|
||||
$edit['pass[pass2]'] = $new_pass;
|
||||
$this->drupalPostForm(NULL, $edit, t('Create new account'));
|
||||
|
||||
// Check user fields.
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertEqual($new_user->getUsername(), $name, 'Username matches.');
|
||||
$this->assertEqual($new_user->getEmail(), $mail, 'Email address matches.');
|
||||
$this->assertTrue(($new_user->getCreatedTime() > REQUEST_TIME - 20), 'Correct creation time.');
|
||||
$this->assertEqual($new_user->isActive(), $config_user_settings->get('register') == USER_REGISTER_VISITORS ? 1 : 0, 'Correct status field.');
|
||||
$this->assertEqual($new_user->getTimezone(), $config_system_date->get('timezone.default'), 'Correct time zone field.');
|
||||
$this->assertEqual($new_user->langcode->value, \Drupal::languageManager()->getDefaultLanguage()->getId(), 'Correct language field.');
|
||||
$this->assertEqual($new_user->preferred_langcode->value, \Drupal::languageManager()->getDefaultLanguage()->getId(), 'Correct preferred language field.');
|
||||
$this->assertEqual($new_user->init->value, $mail, 'Correct init field.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests username and email field constraints on user registration.
|
||||
*
|
||||
* @see \Drupal\user\Plugin\Validation\Constraint\UserNameUnique
|
||||
* @see \Drupal\user\Plugin\Validation\Constraint\UserMailUnique
|
||||
*/
|
||||
public function testUniqueFields() {
|
||||
$account = $this->drupalCreateUser();
|
||||
|
||||
$edit = ['mail' => 'test@example.com', 'name' => $account->getUsername()];
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->assertRaw(new FormattableMarkup('The username %value is already taken.', ['%value' => $account->getUsername()]));
|
||||
|
||||
$edit = ['mail' => $account->getEmail(), 'name' => $this->randomString()];
|
||||
$this->drupalPostForm('user/register', $edit, t('Create new account'));
|
||||
$this->assertRaw(new FormattableMarkup('The email address %value is already taken.', ['%value' => $account->getEmail()]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests Field API fields on user registration forms.
|
||||
*/
|
||||
public function testRegistrationWithUserFields() {
|
||||
// Create a field on 'user' entity type.
|
||||
$field_storage = FieldStorageConfig::create([
|
||||
'field_name' => 'test_user_field',
|
||||
'entity_type' => 'user',
|
||||
'type' => 'test_field',
|
||||
'cardinality' => 1,
|
||||
]);
|
||||
$field_storage->save();
|
||||
$field = FieldConfig::create([
|
||||
'field_storage' => $field_storage,
|
||||
'label' => 'Some user field',
|
||||
'bundle' => 'user',
|
||||
'required' => TRUE,
|
||||
]);
|
||||
$field->save();
|
||||
entity_get_form_display('user', 'user', 'default')
|
||||
->setComponent('test_user_field', ['type' => 'test_field_widget'])
|
||||
->save();
|
||||
entity_get_form_display('user', 'user', 'register')
|
||||
->save();
|
||||
|
||||
// Check that the field does not appear on the registration form.
|
||||
$this->drupalGet('user/register');
|
||||
$this->assertNoText($field->label(), 'The field does not appear on user registration form');
|
||||
$this->assertCacheTag('config:core.entity_form_display.user.user.register');
|
||||
$this->assertCacheTag('config:user.settings');
|
||||
|
||||
// Have the field appear on the registration form.
|
||||
entity_get_form_display('user', 'user', 'register')
|
||||
->setComponent('test_user_field', ['type' => 'test_field_widget'])
|
||||
->save();
|
||||
|
||||
$this->drupalGet('user/register');
|
||||
$this->assertText($field->label(), 'The field appears on user registration form');
|
||||
$this->assertRegistrationFormCacheTagsWithUserFields();
|
||||
|
||||
// Check that validation errors are correctly reported.
|
||||
$edit = [];
|
||||
$edit['name'] = $name = $this->randomMachineName();
|
||||
$edit['mail'] = $mail = $edit['name'] . '@example.com';
|
||||
// Missing input in required field.
|
||||
$edit['test_user_field[0][value]'] = '';
|
||||
$this->drupalPostForm(NULL, $edit, t('Create new account'));
|
||||
$this->assertRegistrationFormCacheTagsWithUserFields();
|
||||
$this->assertRaw(t('@name field is required.', ['@name' => $field->label()]), 'Field validation error was correctly reported.');
|
||||
// Invalid input.
|
||||
$edit['test_user_field[0][value]'] = '-1';
|
||||
$this->drupalPostForm(NULL, $edit, t('Create new account'));
|
||||
$this->assertRegistrationFormCacheTagsWithUserFields();
|
||||
$this->assertRaw(t('%name does not accept the value -1.', ['%name' => $field->label()]), 'Field validation error was correctly reported.');
|
||||
|
||||
// Submit with valid data.
|
||||
$value = rand(1, 255);
|
||||
$edit['test_user_field[0][value]'] = $value;
|
||||
$this->drupalPostForm(NULL, $edit, t('Create new account'));
|
||||
// Check user fields.
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertEqual($new_user->test_user_field->value, $value, 'The field value was correctly saved.');
|
||||
|
||||
// Check that the 'add more' button works.
|
||||
$field_storage->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
|
||||
$field_storage->save();
|
||||
$this->drupalGet('user/register');
|
||||
$this->assertRegistrationFormCacheTagsWithUserFields();
|
||||
// Add two inputs.
|
||||
$value = rand(1, 255);
|
||||
$edit = [];
|
||||
$edit['test_user_field[0][value]'] = $value;
|
||||
$this->drupalPostForm(NULL, $edit, t('Add another item'));
|
||||
$this->drupalPostForm(NULL, $edit, t('Add another item'));
|
||||
// Submit with three values.
|
||||
$edit['test_user_field[1][value]'] = $value + 1;
|
||||
$edit['test_user_field[2][value]'] = $value + 2;
|
||||
$edit['name'] = $name = $this->randomMachineName();
|
||||
$edit['mail'] = $mail = $edit['name'] . '@example.com';
|
||||
$this->drupalPostForm(NULL, $edit, t('Create new account'));
|
||||
// Check user fields.
|
||||
$accounts = $this->container->get('entity_type.manager')->getStorage('user')
|
||||
->loadByProperties(['name' => $name, 'mail' => $mail]);
|
||||
$new_user = reset($accounts);
|
||||
$this->assertEqual($new_user->test_user_field[0]->value, $value, 'The field value was correctly saved.');
|
||||
$this->assertEqual($new_user->test_user_field[1]->value, $value + 1, 'The field value was correctly saved.');
|
||||
$this->assertEqual($new_user->test_user_field[2]->value, $value + 2, 'The field value was correctly saved.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the presence of cache tags on registration form with user fields.
|
||||
*/
|
||||
protected function assertRegistrationFormCacheTagsWithUserFields() {
|
||||
$this->assertCacheTag('config:core.entity_form_display.user.user.register');
|
||||
$this->assertCacheTag('config:field.field.user.user.test_user_field');
|
||||
$this->assertCacheTag('config:field.storage.user.test_user_field');
|
||||
$this->assertCacheTag('config:user.settings');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
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 BrowserTestBase {
|
||||
|
||||
/**
|
||||
* 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' => '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));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests that users can be assigned and unassigned roles.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserRolesAssignmentTest extends BrowserTestBase {
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$admin_user = $this->drupalCreateUser(['administer permissions', 'administer users']);
|
||||
$this->drupalLogin($admin_user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a user can be assigned a role and that the role can be removed
|
||||
* again.
|
||||
*/
|
||||
public function testAssignAndRemoveRole() {
|
||||
$rid = $this->drupalCreateRole(['administer users']);
|
||||
$account = $this->drupalCreateUser();
|
||||
|
||||
// Assign the role to the user.
|
||||
$this->drupalPostForm('user/' . $account->id() . '/edit', ["roles[$rid]" => $rid], t('Save'));
|
||||
$this->assertText(t('The changes have been saved.'));
|
||||
$this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.');
|
||||
$this->userLoadAndCheckRoleAssigned($account, $rid);
|
||||
|
||||
// Remove the role from the user.
|
||||
$this->drupalPostForm('user/' . $account->id() . '/edit', ["roles[$rid]" => FALSE], t('Save'));
|
||||
$this->assertText(t('The changes have been saved.'));
|
||||
$this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.');
|
||||
$this->userLoadAndCheckRoleAssigned($account, $rid, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when creating a user the role can be assigned. And that it can
|
||||
* be removed again.
|
||||
*/
|
||||
public function testCreateUserWithRole() {
|
||||
$rid = $this->drupalCreateRole(['administer users']);
|
||||
// Create a new user and add the role at the same time.
|
||||
$edit = [
|
||||
'name' => $this->randomMachineName(),
|
||||
'mail' => $this->randomMachineName() . '@example.com',
|
||||
'pass[pass1]' => $pass = $this->randomString(),
|
||||
'pass[pass2]' => $pass,
|
||||
"roles[$rid]" => $rid,
|
||||
];
|
||||
$this->drupalPostForm('admin/people/create', $edit, t('Create new account'));
|
||||
$this->assertText(t('Created a new user account for @name.', ['@name' => $edit['name']]));
|
||||
// Get the newly added user.
|
||||
$account = user_load_by_name($edit['name']);
|
||||
|
||||
$this->drupalGet('user/' . $account->id() . '/edit');
|
||||
$this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.');
|
||||
$this->userLoadAndCheckRoleAssigned($account, $rid);
|
||||
|
||||
// Remove the role again.
|
||||
$this->drupalPostForm('user/' . $account->id() . '/edit', ["roles[$rid]" => FALSE], t('Save'));
|
||||
$this->assertText(t('The changes have been saved.'));
|
||||
$this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.');
|
||||
$this->userLoadAndCheckRoleAssigned($account, $rid, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check role on user object.
|
||||
*
|
||||
* @param object $account
|
||||
* The user account to check.
|
||||
* @param string $rid
|
||||
* The role ID to search for.
|
||||
* @param bool $is_assigned
|
||||
* (optional) Whether to assert that $rid exists (TRUE) or not (FALSE).
|
||||
* Defaults to TRUE.
|
||||
*/
|
||||
private function userLoadAndCheckRoleAssigned($account, $rid, $is_assigned = TRUE) {
|
||||
$user_storage = $this->container->get('entity.manager')->getStorage('user');
|
||||
$user_storage->resetCache([$account->id()]);
|
||||
$account = $user_storage->load($account->id());
|
||||
if ($is_assigned) {
|
||||
$this->assertFalse(array_search($rid, $account->getRoles()) === FALSE, 'The role is present in the user object.');
|
||||
}
|
||||
else {
|
||||
$this->assertTrue(array_search($rid, $account->getRoles()) === FALSE, 'The role is not present in the user object.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Tests account saving for arbitrary new uid.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserSaveTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Test creating a user with arbitrary uid.
|
||||
*/
|
||||
public function testUserImport() {
|
||||
// User ID must be a number that is not in the database.
|
||||
|
||||
$uids = \Drupal::entityManager()->getStorage('user')->getQuery()
|
||||
->sort('uid', 'DESC')
|
||||
->range(0, 1)
|
||||
->execute();
|
||||
$max_uid = reset($uids);
|
||||
$test_uid = $max_uid + mt_rand(1000, 1000000);
|
||||
$test_name = $this->randomMachineName();
|
||||
|
||||
// Create the base user, based on drupalCreateUser().
|
||||
$user = User::create([
|
||||
'name' => $test_name,
|
||||
'uid' => $test_uid,
|
||||
'mail' => $test_name . '@example.com',
|
||||
'pass' => user_password(),
|
||||
'status' => 1,
|
||||
]);
|
||||
$user->enforceIsNew();
|
||||
$user->save();
|
||||
|
||||
// Test if created user exists.
|
||||
$user_by_uid = User::load($test_uid);
|
||||
$this->assertTrue($user_by_uid, 'Loading user by uid.');
|
||||
|
||||
$user_by_name = user_load_by_name($test_name);
|
||||
$this->assertTrue($user_by_name, 'Loading user by name.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that an existing password is unset after the user was saved.
|
||||
*/
|
||||
public function testExistingPasswordRemoval() {
|
||||
/** @var \Drupal\user\Entity\User $user */
|
||||
$user = User::create(['name' => $this->randomMachineName()]);
|
||||
$user->save();
|
||||
$user->setExistingPassword('existing password');
|
||||
$this->assertNotNull($user->pass->existing);
|
||||
$user->save();
|
||||
$this->assertNull($user->pass->existing);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests the user search page and verifies that sensitive information is hidden
|
||||
* from unauthorized users.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserSearchTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['search'];
|
||||
|
||||
public function testUserSearch() {
|
||||
// Verify that a user without 'administer users' permission cannot search
|
||||
// for users by email address. Additionally, ensure that the username has a
|
||||
// plus sign to ensure searching works with that.
|
||||
$user1 = $this->drupalCreateUser(['access user profiles', 'search content'], "foo+bar");
|
||||
$this->drupalLogin($user1);
|
||||
$keys = $user1->getEmail();
|
||||
$edit = ['keys' => $keys];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertText(t('Your search yielded no results.'), 'Search by email did not work for non-admin user');
|
||||
$this->assertText('no results', 'Search by email gave no-match message');
|
||||
|
||||
// Verify that a non-matching query gives an appropriate message.
|
||||
$keys = 'nomatch';
|
||||
$edit = ['keys' => $keys];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertText('no results', 'Non-matching search gave appropriate message');
|
||||
|
||||
// Verify that a user with search permission can search for users by name.
|
||||
$keys = $user1->getUsername();
|
||||
$edit = ['keys' => $keys];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertLink($keys, 0, 'Search by username worked for non-admin user');
|
||||
|
||||
// Verify that searching by sub-string works too.
|
||||
$subkey = substr($keys, 1, 5);
|
||||
$edit = ['keys' => $subkey];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertLink($keys, 0, 'Search by username substring worked for non-admin user');
|
||||
|
||||
// Verify that wildcard search works.
|
||||
$subkey = substr($keys, 0, 2) . '*' . substr($keys, 4, 2);
|
||||
$edit = ['keys' => $subkey];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertLink($keys, 0, 'Search with wildcard worked for non-admin user');
|
||||
|
||||
// Verify that a user with 'administer users' permission can search by
|
||||
// email.
|
||||
$user2 = $this->drupalCreateUser(['administer users', 'access user profiles', 'search content']);
|
||||
$this->drupalLogin($user2);
|
||||
$keys = $user2->getEmail();
|
||||
$edit = ['keys' => $keys];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertText($keys, 'Search by email works for administrative user');
|
||||
$this->assertText($user2->getUsername(), 'Search by email resulted in username on page for administrative user');
|
||||
|
||||
// Verify that a substring works too for email.
|
||||
$subkey = substr($keys, 1, 5);
|
||||
$edit = ['keys' => $subkey];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertText($keys, 'Search by email substring works for administrative user');
|
||||
$this->assertText($user2->getUsername(), 'Search by email substring resulted in username on page for administrative user');
|
||||
|
||||
// Verify that wildcard search works for email
|
||||
$subkey = substr($keys, 0, 2) . '*' . substr($keys, 4, 2);
|
||||
$edit = ['keys' => $subkey];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertText($user2->getUsername(), 'Search for email wildcard resulted in username on page for administrative user');
|
||||
|
||||
// Verify that if they search by user name, they see email address too.
|
||||
$keys = $user1->getUsername();
|
||||
$edit = ['keys' => $keys];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertText($keys, 'Search by username works for admin user');
|
||||
$this->assertText($user1->getEmail(), 'Search by username for admin shows email address too');
|
||||
|
||||
// Create a blocked user.
|
||||
$blocked_user = $this->drupalCreateUser();
|
||||
$blocked_user->block();
|
||||
$blocked_user->save();
|
||||
|
||||
// Verify that users with "administer users" permissions can see blocked
|
||||
// accounts in search results.
|
||||
$edit = ['keys' => $blocked_user->getUsername()];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertText($blocked_user->getUsername(), 'Blocked users are listed on the user search results for users with the "administer users" permission.');
|
||||
|
||||
// Verify that users without "administer users" permissions do not see
|
||||
// blocked accounts in search results.
|
||||
$this->drupalLogin($user1);
|
||||
$edit = ['keys' => $blocked_user->getUsername()];
|
||||
$this->drupalPostForm('search/user', $edit, t('Search'));
|
||||
$this->assertText(t('Your search yielded no results.'), 'Blocked users are hidden from the user search results.');
|
||||
|
||||
// Create a user without search permission, and one without user page view
|
||||
// permission. Verify that neither one can access the user search page.
|
||||
$user3 = $this->drupalCreateUser(['search content']);
|
||||
$this->drupalLogin($user3);
|
||||
$this->drupalGet('search/user');
|
||||
$this->assertResponse('403', 'User without user profile access cannot search');
|
||||
|
||||
$user4 = $this->drupalCreateUser(['access user profiles']);
|
||||
$this->drupalLogin($user4);
|
||||
$this->drupalGet('search/user');
|
||||
$this->assertResponse('403', 'User without search permission cannot search');
|
||||
$this->drupalLogout();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Core\Datetime\Entity\DateFormat;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Set a user time zone and verify that dates are displayed in local time.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserTimeZoneTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* 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.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\User;
|
||||
|
||||
/**
|
||||
* Generates text using placeholders for dummy content to check user token
|
||||
* replacement.
|
||||
*
|
||||
* @group user
|
||||
*/
|
||||
class UserTokenReplaceTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['language', 'user_hooks_test'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
ConfigurableLanguage::createFromLangcode('de')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a user, then tests the tokens generated from it.
|
||||
*/
|
||||
public function testUserTokenReplacement() {
|
||||
$token_service = \Drupal::token();
|
||||
$language_interface = \Drupal::languageManager()->getCurrentLanguage();
|
||||
$url_options = [
|
||||
'absolute' => TRUE,
|
||||
'language' => $language_interface,
|
||||
];
|
||||
|
||||
\Drupal::state()->set('user_hooks_test_user_format_name_alter', TRUE);
|
||||
\Drupal::state()->set('user_hooks_test_user_format_name_alter_safe', TRUE);
|
||||
|
||||
// Create two users and log them in one after another.
|
||||
$user1 = $this->drupalCreateUser([]);
|
||||
$user2 = $this->drupalCreateUser([]);
|
||||
$this->drupalLogin($user1);
|
||||
$this->drupalLogout();
|
||||
$this->drupalLogin($user2);
|
||||
|
||||
$account = User::load($user1->id());
|
||||
$global_account = User::load(\Drupal::currentUser()->id());
|
||||
|
||||
// Generate and test tokens.
|
||||
$tests = [];
|
||||
$tests['[user:uid]'] = $account->id();
|
||||
$tests['[user:name]'] = $account->getAccountName();
|
||||
$tests['[user:account-name]'] = $account->getAccountName();
|
||||
$tests['[user:display-name]'] = $account->getDisplayName();
|
||||
$tests['[user:mail]'] = $account->getEmail();
|
||||
$tests['[user:url]'] = $account->url('canonical', $url_options);
|
||||
$tests['[user:edit-url]'] = $account->url('edit-form', $url_options);
|
||||
$tests['[user:last-login]'] = format_date($account->getLastLoginTime(), 'medium', '', NULL, $language_interface->getId());
|
||||
$tests['[user:last-login:short]'] = format_date($account->getLastLoginTime(), 'short', '', NULL, $language_interface->getId());
|
||||
$tests['[user:created]'] = format_date($account->getCreatedTime(), 'medium', '', NULL, $language_interface->getId());
|
||||
$tests['[user:created:short]'] = format_date($account->getCreatedTime(), 'short', '', NULL, $language_interface->getId());
|
||||
$tests['[current-user:name]'] = $global_account->getAccountName();
|
||||
$tests['[current-user:account-name]'] = $global_account->getAccountName();
|
||||
$tests['[current-user:display-name]'] = $global_account->getDisplayName();
|
||||
|
||||
$base_bubbleable_metadata = BubbleableMetadata::createFromObject($account);
|
||||
$metadata_tests = [];
|
||||
$metadata_tests['[user:uid]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[user:name]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[user:account-name]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[user:display-name]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[user:mail]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[user:url]'] = $base_bubbleable_metadata;
|
||||
$metadata_tests['[user:edit-url]'] = $base_bubbleable_metadata;
|
||||
$bubbleable_metadata = clone $base_bubbleable_metadata;
|
||||
// This test runs with the Language module enabled, which means config is
|
||||
// overridden by LanguageConfigFactoryOverride (to provide translations of
|
||||
// config). This causes the interface language cache context to be added for
|
||||
// config entities. The four next tokens use DateFormat Config entities, and
|
||||
// therefore have the interface language cache context.
|
||||
$bubbleable_metadata->addCacheContexts(['languages:language_interface']);
|
||||
$metadata_tests['[user:last-login]'] = $bubbleable_metadata->addCacheTags(['rendered']);
|
||||
$metadata_tests['[user:last-login:short]'] = $bubbleable_metadata;
|
||||
$metadata_tests['[user:created]'] = $bubbleable_metadata;
|
||||
$metadata_tests['[user:created:short]'] = $bubbleable_metadata;
|
||||
$metadata_tests['[current-user:name]'] = $base_bubbleable_metadata->merge(BubbleableMetadata::createFromObject($global_account)->addCacheContexts(['user']));
|
||||
$metadata_tests['[current-user:account-name]'] = $base_bubbleable_metadata->merge(BubbleableMetadata::createFromObject($global_account)->addCacheContexts(['user']));
|
||||
$metadata_tests['[current-user:display-name]'] = $base_bubbleable_metadata->merge(BubbleableMetadata::createFromObject($global_account)->addCacheContexts(['user']));
|
||||
|
||||
// Test to make sure that we generated something for each token.
|
||||
$this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.');
|
||||
|
||||
foreach ($tests as $input => $expected) {
|
||||
$bubbleable_metadata = new BubbleableMetadata();
|
||||
$output = $token_service->replace($input, ['user' => $account], ['langcode' => $language_interface->getId()], $bubbleable_metadata);
|
||||
$this->assertEqual($output, $expected, new FormattableMarkup('User token %token replaced.', ['%token' => $input]));
|
||||
$this->assertEqual($bubbleable_metadata, $metadata_tests[$input]);
|
||||
}
|
||||
|
||||
// Generate tokens for the anonymous user.
|
||||
$anonymous_user = User::load(0);
|
||||
$tests = [];
|
||||
$tests['[user:uid]'] = t('not yet assigned');
|
||||
$tests['[user:display-name]'] = $anonymous_user->getDisplayName();
|
||||
|
||||
$base_bubbleable_metadata = BubbleableMetadata::createFromObject($anonymous_user);
|
||||
$metadata_tests = [];
|
||||
$metadata_tests['[user:uid]'] = $base_bubbleable_metadata;
|
||||
$bubbleable_metadata = clone $base_bubbleable_metadata;
|
||||
$bubbleable_metadata->addCacheableDependency(\Drupal::config('user.settings'));
|
||||
$metadata_tests['[user:display-name]'] = $bubbleable_metadata;
|
||||
|
||||
foreach ($tests as $input => $expected) {
|
||||
$bubbleable_metadata = new BubbleableMetadata();
|
||||
$output = $token_service->replace($input, ['user' => $anonymous_user], ['langcode' => $language_interface->getId()], $bubbleable_metadata);
|
||||
$this->assertEqual($output, $expected, format_string('Sanitized user token %token replaced.', ['%token' => $input]));
|
||||
$this->assertEqual($bubbleable_metadata, $metadata_tests[$input]);
|
||||
}
|
||||
|
||||
// Generate login and cancel link.
|
||||
$tests = [];
|
||||
$tests['[user:one-time-login-url]'] = user_pass_reset_url($account);
|
||||
$tests['[user:cancel-url]'] = user_cancel_url($account);
|
||||
|
||||
// Generate tokens with interface language.
|
||||
$link = \Drupal::url('user.page', [], ['absolute' => TRUE]);
|
||||
foreach ($tests as $input => $expected) {
|
||||
$output = $token_service->replace($input, ['user' => $account], ['langcode' => $language_interface->getId(), 'callback' => 'user_mail_tokens', 'clear' => TRUE]);
|
||||
$this->assertTrue(strpos($output, $link) === 0, 'Generated URL is in interface language.');
|
||||
}
|
||||
|
||||
// Generate tokens with the user's preferred language.
|
||||
$account->preferred_langcode = 'de';
|
||||
$account->save();
|
||||
$link = \Drupal::url('user.page', [], ['language' => \Drupal::languageManager()->getLanguage($account->getPreferredLangcode()), 'absolute' => TRUE]);
|
||||
foreach ($tests as $input => $expected) {
|
||||
$output = $token_service->replace($input, ['user' => $account], ['callback' => 'user_mail_tokens', 'clear' => TRUE]);
|
||||
$this->assertTrue(strpos($output, $link) === 0, "Generated URL is in the user's preferred language.");
|
||||
}
|
||||
|
||||
// Generate tokens with one specific language.
|
||||
$link = \Drupal::url('user.page', [], ['language' => \Drupal::languageManager()->getLanguage('de'), 'absolute' => TRUE]);
|
||||
foreach ($tests as $input => $expected) {
|
||||
foreach ([$user1, $user2] as $account) {
|
||||
$output = $token_service->replace($input, ['user' => $account], ['langcode' => 'de', 'callback' => 'user_mail_tokens', 'clear' => TRUE]);
|
||||
$this->assertTrue(strpos($output, $link) === 0, "Generated URL in the requested language.");
|
||||
}
|
||||
}
|
||||
|
||||
// Generate user display name tokens when safe markup is returned.
|
||||
// @see user_hooks_test_user_format_name_alter()
|
||||
\Drupal::state()->set('user_hooks_test_user_format_name_alter_safe', TRUE);
|
||||
$input = '[user:display-name] [current-user:display-name]';
|
||||
$expected = "<em>{$user1->id()}</em> <em>{$user2->id()}</em>";
|
||||
$output = $token_service->replace($input, ['user' => $user1]);
|
||||
$this->assertEqual($output, $expected, new FormattableMarkup('User token %token does not escape safe markup.', ['%token' => 'display-name']));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional;
|
||||
|
||||
use Drupal\Tests\content_translation\Functional\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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test translated user deletion.
|
||||
*/
|
||||
public function testTranslatedUserDeletion() {
|
||||
$this->drupalLogin($this->administrator);
|
||||
$entity_id = $this->createEntity($this->getNewEntityValues('en'), 'en');
|
||||
|
||||
$entity = $this->container->get('entity_type.manager')
|
||||
->getStorage($this->entityTypeId)
|
||||
->load($entity_id);
|
||||
$translated_entity = $entity->addTranslation('fr');
|
||||
$translated_entity->save();
|
||||
|
||||
$url = $entity->toUrl(
|
||||
'edit-form',
|
||||
['language' => $this->container->get('language_manager')->getLanguage('en')]
|
||||
);
|
||||
$this->drupalPostForm($url, [], t('Cancel account'));
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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, '');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Views;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\system\Tests\Cache\AssertPageCacheContextsAndTagsTrait;
|
||||
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 {
|
||||
|
||||
use AssertPageCacheContextsAndTagsTrait;
|
||||
|
||||
/**
|
||||
* 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', 'views_test_data'],
|
||||
];
|
||||
$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', 'views_test_data'],
|
||||
];
|
||||
$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, '');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
$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.
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
$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()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Views;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
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(new FormattableMarkup('No access to execute %action on the @entity_type_label %entity_label.', [
|
||||
'%action' => 'Block the selected user(s)',
|
||||
'@entity_type_label' => 'User',
|
||||
'%entity_label' => $no_edit_user->label(),
|
||||
]));
|
||||
|
||||
// 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.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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']));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Views;
|
||||
|
||||
use Drupal\Tests\views\Functional\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($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
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.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\Views;
|
||||
|
||||
use Drupal\views\Views;
|
||||
use Drupal\Tests\views\Functional\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($import_test_views = TRUE) {
|
||||
parent::setUp($import_test_views);
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\Tests\user\Functional\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>');
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue