Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
|
@ -0,0 +1,7 @@
|
|||
id: user.register
|
||||
label: Register
|
||||
status: true
|
||||
targetEntityType: user
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
|
@ -0,0 +1,8 @@
|
|||
id: user.compact
|
||||
label: Compact
|
||||
status: true
|
||||
cache: true
|
||||
targetEntityType: user
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
|
@ -0,0 +1,8 @@
|
|||
id: user.full
|
||||
label: 'User account'
|
||||
status: false
|
||||
cache: true
|
||||
targetEntityType: user
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
|
@ -0,0 +1,9 @@
|
|||
id: user_block_user_action
|
||||
label: 'Block the selected user(s)'
|
||||
status: true
|
||||
langcode: en
|
||||
type: user
|
||||
plugin: user_block_user_action
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
|
@ -0,0 +1,9 @@
|
|||
id: user_cancel_user_action
|
||||
label: 'Cancel the selected user account(s)'
|
||||
status: true
|
||||
langcode: en
|
||||
type: user
|
||||
plugin: user_cancel_user_action
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
|
@ -0,0 +1,9 @@
|
|||
id: user_unblock_user_action
|
||||
label: 'Unblock the selected user(s)'
|
||||
status: true
|
||||
langcode: en
|
||||
type: user
|
||||
plugin: user_unblock_user_action
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
5
core/modules/user/config/install/user.flood.yml
Normal file
5
core/modules/user/config/install/user.flood.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
uid_only: false
|
||||
ip_limit: 50
|
||||
ip_window: 3600
|
||||
user_limit: 5
|
||||
user_window: 21600
|
28
core/modules/user/config/install/user.mail.yml
Normal file
28
core/modules/user/config/install/user.mail.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
cancel_confirm:
|
||||
body: "[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"
|
||||
subject: 'Account cancellation request for [user:name] at [site:name]'
|
||||
password_reset:
|
||||
body: "[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"
|
||||
subject: 'Replacement login information for [user:name] at [site:name]'
|
||||
register_admin_created:
|
||||
body: "[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"
|
||||
subject: 'An administrator created an account for you at [site:name]'
|
||||
register_no_approval_required:
|
||||
body: "[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"
|
||||
subject: 'Account details for [user:name] at [site:name]'
|
||||
register_pending_approval:
|
||||
body: "[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"
|
||||
subject: 'Account details for [user:name] at [site:name] (pending admin approval)'
|
||||
register_pending_approval_admin:
|
||||
body: "[user:name] has applied for an account.\n\n[user:edit-url]"
|
||||
subject: 'Account details for [user:name] at [site:name] (pending admin approval)'
|
||||
status_activated:
|
||||
body: "[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"
|
||||
subject: 'Account details for [user:name] at [site:name] (approved)'
|
||||
status_blocked:
|
||||
body: "[user:name],\n\nYour account on [site:name] has been blocked.\n\n-- [site:name] team"
|
||||
subject: 'Account details for [user:name] at [site:name] (blocked)'
|
||||
status_canceled:
|
||||
body: "[user:name],\n\nYour account on [site:name] has been canceled.\n\n-- [site:name] team"
|
||||
subject: 'Account details for [user:name] at [site:name] (canceled)'
|
||||
langcode: en
|
7
core/modules/user/config/install/user.role.anonymous.yml
Normal file
7
core/modules/user/config/install/user.role.anonymous.yml
Normal file
|
@ -0,0 +1,7 @@
|
|||
id: anonymous
|
||||
label: 'Anonymous user'
|
||||
weight: 0
|
||||
langcode: en
|
||||
status: true
|
||||
is_admin: false
|
||||
dependencies: { }
|
|
@ -0,0 +1,7 @@
|
|||
id: authenticated
|
||||
label: 'Authenticated user'
|
||||
weight: 1
|
||||
langcode: en
|
||||
status: true
|
||||
is_admin: false
|
||||
dependencies: { }
|
16
core/modules/user/config/install/user.settings.yml
Normal file
16
core/modules/user/config/install/user.settings.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
anonymous: Anonymous
|
||||
verify_mail: true
|
||||
notify:
|
||||
cancel_confirm: true
|
||||
password_reset: true
|
||||
status_activated: true
|
||||
status_blocked: false
|
||||
status_canceled: false
|
||||
register_admin_created: true
|
||||
register_no_approval_required: true
|
||||
register_pending_approval: true
|
||||
register: visitors
|
||||
cancel_method: user_cancel_block
|
||||
password_reset_timeout: 86400
|
||||
password_strength: true
|
||||
langcode: en
|
12
core/modules/user/config/optional/rdf.mapping.user.user.yml
Normal file
12
core/modules/user/config/optional/rdf.mapping.user.user.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
id: user.user
|
||||
targetEntityType: user
|
||||
bundle: user
|
||||
types:
|
||||
- 'schema:Person'
|
||||
fieldMappings:
|
||||
name:
|
||||
properties:
|
||||
- 'schema:name'
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
|
@ -0,0 +1,11 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: user_search
|
||||
label: Users
|
||||
path: user
|
||||
weight: 0
|
||||
plugin: user_search
|
||||
configuration: { }
|
|
@ -0,0 +1,890 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: user_admin_people
|
||||
label: People
|
||||
module: user
|
||||
description: 'Find and manage people interacting with your site.'
|
||||
tag: default
|
||||
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: perm
|
||||
options:
|
||||
perm: 'administer users'
|
||||
cache:
|
||||
type: tag
|
||||
query:
|
||||
type: views_query
|
||||
options:
|
||||
disable_sql_rewrite: false
|
||||
distinct: false
|
||||
replica: false
|
||||
query_comment: ''
|
||||
query_tags: { }
|
||||
exposed_form:
|
||||
type: basic
|
||||
options:
|
||||
submit_button: Filter
|
||||
reset_button: true
|
||||
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: 50
|
||||
offset: 0
|
||||
id: 0
|
||||
total_pages: 0
|
||||
tags:
|
||||
previous: '‹ previous'
|
||||
next: 'next ›'
|
||||
first: '« first'
|
||||
last: 'last »'
|
||||
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
|
||||
quantity: 9
|
||||
style:
|
||||
type: table
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
override: true
|
||||
sticky: false
|
||||
summary: ''
|
||||
columns:
|
||||
user_bulk_form: user_bulk_form
|
||||
name: name
|
||||
status: status
|
||||
rid: rid
|
||||
created: created
|
||||
access: access
|
||||
edit_node: edit_node
|
||||
dropbutton: dropbutton
|
||||
info:
|
||||
user_bulk_form:
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
name:
|
||||
sortable: true
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
status:
|
||||
sortable: true
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: priority-low
|
||||
rid:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: priority-low
|
||||
created:
|
||||
sortable: true
|
||||
default_sort_order: desc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: priority-low
|
||||
access:
|
||||
sortable: true
|
||||
default_sort_order: desc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: priority-low
|
||||
edit_node:
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: priority-low
|
||||
dropbutton:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
default: created
|
||||
empty_table: true
|
||||
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: 'Bulk update'
|
||||
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: user_bulk_form
|
||||
entity_type: user
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Username
|
||||
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
|
||||
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
|
||||
plugin_id: field
|
||||
type: boolean
|
||||
settings:
|
||||
format: custom
|
||||
format_custom_true: 'Active'
|
||||
format_custom_false: 'Blocked'
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
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: ul
|
||||
separator: ', '
|
||||
plugin_id: user_roles
|
||||
created:
|
||||
id: created
|
||||
table: users_field_data
|
||||
field: created
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: 'Member for'
|
||||
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
|
||||
date_format: 'raw time ago'
|
||||
custom_date_format: ''
|
||||
timezone: ''
|
||||
plugin_id: date
|
||||
entity_type: user
|
||||
entity_field: created
|
||||
access:
|
||||
id: access
|
||||
table: users_field_data
|
||||
field: access
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: 'Last access'
|
||||
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
|
||||
date_format: 'time ago'
|
||||
custom_date_format: ''
|
||||
timezone: ''
|
||||
plugin_id: date
|
||||
entity_type: user
|
||||
entity_field: access
|
||||
operations:
|
||||
id: operations
|
||||
table: users
|
||||
field: operations
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: Operations
|
||||
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
|
||||
destination: true
|
||||
entity_type: user
|
||||
plugin_id: entity_operations
|
||||
mail:
|
||||
id: mail
|
||||
table: users_field_data
|
||||
field: mail
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
label: ''
|
||||
exclude: true
|
||||
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
|
||||
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
|
||||
plugin_id: field
|
||||
entity_type: user
|
||||
entity_field: mail
|
||||
filters:
|
||||
combine:
|
||||
id: combine
|
||||
table: views
|
||||
field: combine
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: contains
|
||||
value: ''
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: combine_op
|
||||
label: 'Name or email contains'
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: combine_op
|
||||
identifier: user
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
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:
|
||||
name: name
|
||||
mail: mail
|
||||
plugin_id: combine
|
||||
roles_target_id:
|
||||
id: roles_target_id
|
||||
table: user__roles
|
||||
field: roles_target_id
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: or
|
||||
value: { }
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: roles_target_id_op
|
||||
label: Role
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: roles_target_id_op
|
||||
identifier: role
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
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: false
|
||||
plugin_id: user_roles
|
||||
permission:
|
||||
id: permission
|
||||
table: user__roles
|
||||
field: permission
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: or
|
||||
value: { }
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: permission_op
|
||||
label: Permission
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: permission_op
|
||||
identifier: permission
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
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: false
|
||||
plugin_id: user_permissions
|
||||
status:
|
||||
id: status
|
||||
table: users_field_data
|
||||
field: status
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: true
|
||||
group: 1
|
||||
exposed: true
|
||||
expose:
|
||||
operator_id: ''
|
||||
label: ''
|
||||
description: ''
|
||||
use_operator: false
|
||||
operator: status_op
|
||||
identifier: status
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
is_grouped: true
|
||||
group_info:
|
||||
label: Status
|
||||
description: ''
|
||||
identifier: status
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items:
|
||||
1:
|
||||
title: Active
|
||||
operator: '='
|
||||
value: '1'
|
||||
2:
|
||||
title: Blocked
|
||||
operator: '='
|
||||
value: '0'
|
||||
plugin_id: boolean
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
default_langcode:
|
||||
id: default_langcode
|
||||
table: users_field_data
|
||||
field: default_langcode
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '='
|
||||
value: true
|
||||
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
|
||||
entity_field: default_langcode
|
||||
plugin_id: boolean
|
||||
uid_raw:
|
||||
id: uid_raw
|
||||
table: users_field_data
|
||||
field: uid_raw
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '!='
|
||||
value:
|
||||
min: ''
|
||||
max: ''
|
||||
value: '0'
|
||||
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
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: numeric
|
||||
entity_type: user
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
table: users_field_data
|
||||
field: created
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: DESC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
granularity: second
|
||||
plugin_id: date
|
||||
entity_type: user
|
||||
entity_field: created
|
||||
title: People
|
||||
empty:
|
||||
area_text_custom:
|
||||
id: area_text_custom
|
||||
table: views
|
||||
field: area_text_custom
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
empty: true
|
||||
tokenize: false
|
||||
content: 'No people available.'
|
||||
plugin_id: text_custom
|
||||
use_more: false
|
||||
use_more_always: false
|
||||
use_more_text: more
|
||||
display_comment: ''
|
||||
use_ajax: false
|
||||
hide_attachment_summary: false
|
||||
show_admin_links: true
|
||||
group_by: false
|
||||
link_url: ''
|
||||
link_display: page_1
|
||||
css_class: ''
|
||||
filter_groups:
|
||||
operator: AND
|
||||
groups:
|
||||
1: AND
|
||||
display_extenders: { }
|
||||
page_1:
|
||||
display_plugin: page
|
||||
id: page_1
|
||||
display_title: Page
|
||||
position: 1
|
||||
display_options:
|
||||
path: admin/people/list
|
||||
show_admin_links: false
|
||||
menu:
|
||||
type: 'default tab'
|
||||
title: List
|
||||
description: 'Find and manage people interacting with your site.'
|
||||
menu_name: admin
|
||||
weight: -10
|
||||
context: ''
|
||||
tab_options:
|
||||
type: normal
|
||||
title: People
|
||||
description: 'Manage user accounts, roles, and permissions.'
|
||||
menu_name: admin
|
||||
weight: 0
|
||||
defaults:
|
||||
show_admin_links: false
|
||||
display_extenders: { }
|
174
core/modules/user/config/optional/views.view.who_s_new.yml
Normal file
174
core/modules/user/config/optional/views.view.who_s_new.yml
Normal file
|
@ -0,0 +1,174 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: who_s_new
|
||||
label: 'Who''s new'
|
||||
module: user
|
||||
description: 'Shows a list of the newest user accounts on the site.'
|
||||
tag: default
|
||||
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: perm
|
||||
options:
|
||||
perm: 'access content'
|
||||
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: some
|
||||
options:
|
||||
items_per_page: 5
|
||||
offset: 0
|
||||
style:
|
||||
type: html_list
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
label: ''
|
||||
plugin_id: field
|
||||
type: user_name
|
||||
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
|
||||
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
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
table: users_field_data
|
||||
field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: '0'
|
||||
group: 1
|
||||
plugin_id: boolean
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
access:
|
||||
id: access
|
||||
table: users_field_data
|
||||
field: access
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '>'
|
||||
value:
|
||||
min: ''
|
||||
max: ''
|
||||
value: '1970-01-01'
|
||||
type: date
|
||||
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
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: date
|
||||
entity_type: user
|
||||
entity_field: access
|
||||
sorts:
|
||||
created:
|
||||
id: created
|
||||
table: users_field_data
|
||||
field: created
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
order: DESC
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
granularity: second
|
||||
plugin_id: date
|
||||
entity_type: user
|
||||
entity_field: created
|
||||
title: 'Who''s new'
|
||||
header: { }
|
||||
footer: { }
|
||||
empty: { }
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
block_1:
|
||||
display_plugin: block
|
||||
id: block_1
|
||||
display_title: 'Who''s new'
|
||||
position: 1
|
||||
display_options:
|
||||
display_description: 'A list of new users'
|
||||
block_description: 'Who''s new'
|
||||
block_category: User
|
203
core/modules/user/config/optional/views.view.who_s_online.yml
Normal file
203
core/modules/user/config/optional/views.view.who_s_online.yml
Normal file
|
@ -0,0 +1,203 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- user
|
||||
id: who_s_online
|
||||
label: 'Who''s online block'
|
||||
module: user
|
||||
description: 'Shows the user names of the most recently active users, and the total number of active users.'
|
||||
tag: default
|
||||
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: perm
|
||||
options:
|
||||
perm: 'access user profiles'
|
||||
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: some
|
||||
options:
|
||||
items_per_page: 10
|
||||
offset: 0
|
||||
style:
|
||||
type: html_list
|
||||
options:
|
||||
grouping: { }
|
||||
row_class: ''
|
||||
default_row_class: true
|
||||
type: ul
|
||||
wrapper_class: item-list
|
||||
class: ''
|
||||
row:
|
||||
type: fields
|
||||
fields:
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
label: ''
|
||||
plugin_id: field
|
||||
type: user_name
|
||||
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
|
||||
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
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
filters:
|
||||
status:
|
||||
value: true
|
||||
table: users_field_data
|
||||
field: status
|
||||
id: status
|
||||
expose:
|
||||
operator: '0'
|
||||
group: 1
|
||||
plugin_id: boolean
|
||||
entity_type: user
|
||||
entity_field: status
|
||||
access:
|
||||
id: access
|
||||
table: users_field_data
|
||||
field: access
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
operator: '>='
|
||||
value:
|
||||
min: ''
|
||||
max: ''
|
||||
value: '-15 minutes'
|
||||
type: offset
|
||||
group: 1
|
||||
exposed: false
|
||||
expose:
|
||||
operator_id: access_op
|
||||
label: 'Last access'
|
||||
description: 'A user is considered online for this long after they have last viewed a page.'
|
||||
use_operator: false
|
||||
operator: access_op
|
||||
identifier: access
|
||||
required: false
|
||||
remember: false
|
||||
multiple: false
|
||||
remember_roles:
|
||||
authenticated: authenticated
|
||||
anonymous: '0'
|
||||
administrator: '0'
|
||||
is_grouped: false
|
||||
group_info:
|
||||
label: ''
|
||||
description: ''
|
||||
identifier: ''
|
||||
optional: true
|
||||
widget: select
|
||||
multiple: false
|
||||
remember: false
|
||||
default_group: All
|
||||
default_group_multiple: { }
|
||||
group_items: { }
|
||||
plugin_id: date
|
||||
entity_type: user
|
||||
entity_field: access
|
||||
sorts:
|
||||
access:
|
||||
id: access
|
||||
table: users_field_data
|
||||
field: access
|
||||
order: DESC
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
exposed: false
|
||||
expose:
|
||||
label: ''
|
||||
granularity: second
|
||||
plugin_id: date
|
||||
entity_type: user
|
||||
entity_field: access
|
||||
title: 'Who''s online'
|
||||
header:
|
||||
result:
|
||||
id: result
|
||||
table: views
|
||||
field: result
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
empty: false
|
||||
content: 'There are currently @total users online.'
|
||||
plugin_id: result
|
||||
footer: { }
|
||||
empty:
|
||||
area_text_custom:
|
||||
id: area_text_custom
|
||||
table: views
|
||||
field: area_text_custom
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
empty: true
|
||||
tokenize: false
|
||||
content: 'There are currently 0 users online.'
|
||||
plugin_id: text_custom
|
||||
relationships: { }
|
||||
arguments: { }
|
||||
who_s_online_block:
|
||||
display_plugin: block
|
||||
id: who_s_online_block
|
||||
display_title: 'Who''s online'
|
||||
position: 1
|
||||
display_options:
|
||||
block_description: 'Who''s online'
|
||||
display_description: 'A list of users that are currently logged in.'
|
194
core/modules/user/config/schema/user.schema.yml
Normal file
194
core/modules/user/config/schema/user.schema.yml
Normal file
|
@ -0,0 +1,194 @@
|
|||
# Schema for the configuration files of the User module.
|
||||
|
||||
user.settings:
|
||||
type: config_object
|
||||
label: 'User settings'
|
||||
mapping:
|
||||
anonymous:
|
||||
type: label
|
||||
label: 'Name'
|
||||
verify_mail:
|
||||
type: boolean
|
||||
label: 'Require email verification when a visitor creates an account'
|
||||
notify:
|
||||
type: mapping
|
||||
label: 'Notify user'
|
||||
mapping:
|
||||
cancel_confirm:
|
||||
type: boolean
|
||||
label: 'Account cancellation confirmation'
|
||||
password_reset:
|
||||
type: boolean
|
||||
label: 'Notify user when password reset'
|
||||
status_activated:
|
||||
type: boolean
|
||||
label: 'Notify user when account is activated'
|
||||
status_blocked:
|
||||
type: boolean
|
||||
label: 'Account blocked'
|
||||
status_canceled:
|
||||
type: boolean
|
||||
label: 'Account canceled'
|
||||
register_admin_created:
|
||||
type: boolean
|
||||
label: 'Welcome (new user created by administrator)'
|
||||
register_no_approval_required:
|
||||
type: boolean
|
||||
label: 'Welcome (no approval required)'
|
||||
register_pending_approval:
|
||||
type: boolean
|
||||
label: 'Welcome (awaiting approval)'
|
||||
register:
|
||||
type: string
|
||||
label: 'Who can register accounts?'
|
||||
cancel_method:
|
||||
type: string
|
||||
label: 'When cancelling a user account'
|
||||
password_reset_timeout:
|
||||
type: integer
|
||||
label: 'Password reset timeout'
|
||||
password_strength:
|
||||
type: boolean
|
||||
label: 'Enable password strength indicator'
|
||||
|
||||
user.mail:
|
||||
type: config_object
|
||||
label: 'Email settings'
|
||||
mapping:
|
||||
cancel_confirm:
|
||||
type: mail
|
||||
label: 'Account cancellation confirmation'
|
||||
password_reset:
|
||||
type: mail
|
||||
label: 'Password recovery'
|
||||
register_admin_created:
|
||||
type: mail
|
||||
label: 'Account created by administrator'
|
||||
register_no_approval_required:
|
||||
type: mail
|
||||
label: 'Registration confirmation (No approval required)'
|
||||
register_pending_approval:
|
||||
type: mail
|
||||
label: 'Registration confirmation (Pending approval)'
|
||||
register_pending_approval_admin:
|
||||
type: mail
|
||||
label: 'Admin (user awaiting approval)'
|
||||
status_activated:
|
||||
type: mail
|
||||
label: 'Account activation'
|
||||
status_blocked:
|
||||
type: mail
|
||||
label: 'Account blocked'
|
||||
status_canceled:
|
||||
type: mail
|
||||
label: 'Account cancelled'
|
||||
|
||||
user.flood:
|
||||
type: config_object
|
||||
label: 'User flood settings'
|
||||
mapping:
|
||||
uid_only:
|
||||
type: boolean
|
||||
label: 'UID only identifier'
|
||||
ip_limit:
|
||||
type: integer
|
||||
label: 'IP limit'
|
||||
ip_window:
|
||||
type: integer
|
||||
label: 'IP window'
|
||||
user_limit:
|
||||
type: integer
|
||||
label: 'User limit'
|
||||
user_window:
|
||||
type: integer
|
||||
label: 'User window'
|
||||
|
||||
user.role.*:
|
||||
type: config_entity
|
||||
label: 'User role settings'
|
||||
mapping:
|
||||
id:
|
||||
type: string
|
||||
label: 'ID'
|
||||
label:
|
||||
type: label
|
||||
label: 'Label'
|
||||
weight:
|
||||
type: integer
|
||||
label: 'User role weight'
|
||||
is_admin:
|
||||
type: boolean
|
||||
label: 'User is admin'
|
||||
permissions:
|
||||
type: sequence
|
||||
label: 'Permissions'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Permission'
|
||||
|
||||
action.configuration.user_add_role_action:
|
||||
type: mapping
|
||||
label: 'Configuration for the add role action'
|
||||
mapping:
|
||||
rid:
|
||||
type: string
|
||||
label: 'The ID of the role to add'
|
||||
|
||||
action.configuration.user_block_user_action:
|
||||
type: action_configuration_default
|
||||
label: 'Block the selected users configuration'
|
||||
|
||||
action.configuration.user_cancel_user_action:
|
||||
type: action_configuration_default
|
||||
label: 'Cancel the selected user accounts configuration'
|
||||
|
||||
action.configuration.user_remove_role_action:
|
||||
type: mapping
|
||||
label: 'Configuration for the remove role action'
|
||||
mapping:
|
||||
rid:
|
||||
type: string
|
||||
label: 'The ID of the role to remove'
|
||||
|
||||
action.configuration.user_unblock_user_action:
|
||||
type: action_configuration_default
|
||||
label: 'Unblock the selected users configuration'
|
||||
|
||||
search.plugin.user_search:
|
||||
type: sequence
|
||||
label: 'User search'
|
||||
|
||||
condition.plugin.user_role:
|
||||
type: condition.plugin
|
||||
mapping:
|
||||
roles:
|
||||
type: sequence
|
||||
sequence:
|
||||
type: string
|
||||
|
||||
entity_reference_selection.default:user:
|
||||
type: entity_reference_selection
|
||||
mapping:
|
||||
filter:
|
||||
type: mapping
|
||||
label: 'Filter settings'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Filter by'
|
||||
role:
|
||||
type: sequence
|
||||
label: 'Restrict to the selected roles'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Role'
|
||||
include_anonymous:
|
||||
type: boolean
|
||||
label: 'Include the anonymous user in the matched entities.'
|
||||
|
||||
field.formatter.settings.user_name:
|
||||
type: mapping
|
||||
mapping:
|
||||
link_to_entity:
|
||||
type: boolean
|
||||
label: 'Link to the user'
|
111
core/modules/user/config/schema/user.views.schema.yml
Normal file
111
core/modules/user/config/schema/user.views.schema.yml
Normal file
|
@ -0,0 +1,111 @@
|
|||
# Schema for the views plugins of the User module.
|
||||
|
||||
views.access.perm:
|
||||
type: mapping
|
||||
label: 'Permission'
|
||||
mapping:
|
||||
perm:
|
||||
type: string
|
||||
label: 'Permission'
|
||||
|
||||
views.access.role:
|
||||
type: mapping
|
||||
label: 'Roles'
|
||||
mapping:
|
||||
role:
|
||||
type: sequence
|
||||
label: 'List of roles'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Role'
|
||||
|
||||
views.argument.user_uid:
|
||||
type: views.argument.numeric
|
||||
label: 'User ID'
|
||||
|
||||
views.argument.user__roles_rid:
|
||||
type: views.argument.many_to_one
|
||||
label: 'Role ID'
|
||||
|
||||
views.argument_validator.user:
|
||||
type: mapping
|
||||
label: 'User'
|
||||
mapping:
|
||||
type:
|
||||
type: string
|
||||
label: 'Type of user filter value to allow'
|
||||
restrict_roles:
|
||||
type: boolean
|
||||
label: 'Restrict user based on role'
|
||||
roles:
|
||||
type: sequence
|
||||
label: 'Restrict to the selected roles'
|
||||
sequence:
|
||||
type: string
|
||||
label: 'Role'
|
||||
|
||||
views.argument_default.user:
|
||||
type: mapping
|
||||
label: 'User ID from URL'
|
||||
mapping:
|
||||
user:
|
||||
type: boolean
|
||||
label: 'Also look for a node and use the node author'
|
||||
|
||||
views.argument_default.current_user:
|
||||
type: boolean
|
||||
label: 'User ID from logged in user'
|
||||
|
||||
views.argument_default.node:
|
||||
type: boolean
|
||||
label: 'Content ID from URL'
|
||||
|
||||
views_field_user:
|
||||
type: views_field
|
||||
mapping:
|
||||
link_to_user:
|
||||
type: boolean
|
||||
label: 'Link this field to its user'
|
||||
|
||||
views.field.user_permissions:
|
||||
type: views.field.prerender_list
|
||||
label: 'List of permission'
|
||||
|
||||
views.field.user_roles:
|
||||
type: views.field.prerender_list
|
||||
label: 'List of roles'
|
||||
|
||||
views.field.user:
|
||||
type: views_field_user
|
||||
label: 'User'
|
||||
|
||||
views.field.user_bulk_form:
|
||||
type: views_field_bulk_form
|
||||
label: 'User operations bulk form'
|
||||
|
||||
views.field.user_data:
|
||||
type: views_field
|
||||
label: 'User data field'
|
||||
mapping:
|
||||
data_module:
|
||||
type: string
|
||||
label: 'Module name'
|
||||
data_name:
|
||||
type: string
|
||||
label: 'Name'
|
||||
|
||||
views.filter.user_current:
|
||||
type: views.filter.boolean
|
||||
label: 'Current user'
|
||||
|
||||
views.filter.user_name:
|
||||
type: views.filter.in_operator
|
||||
label: 'User name'
|
||||
|
||||
views.filter.user_permissions:
|
||||
type: views.filter.many_to_one
|
||||
label: 'Permission'
|
||||
|
||||
views.filter.user_roles:
|
||||
type: views.filter.many_to_one
|
||||
label: 'Role'
|
22
core/modules/user/css/user.admin.css
Normal file
22
core/modules/user/css/user.admin.css
Normal file
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* @file
|
||||
* Admin styling for the User module.
|
||||
*/
|
||||
|
||||
/* Permissions page */
|
||||
.permissions .module {
|
||||
font-weight: bold;
|
||||
}
|
||||
.permissions .permission {
|
||||
padding-left: 1.5em; /* LTR */
|
||||
}
|
||||
[dir="rtl"] .permissions .permission {
|
||||
padding-left: 0;
|
||||
padding-right: 1.5em;
|
||||
}
|
||||
|
||||
/* Account settings */
|
||||
.user-admin-settings .details-description {
|
||||
font-size: 0.85em;
|
||||
padding-bottom: .5em;
|
||||
}
|
15
core/modules/user/css/user.icons.theme.css
Normal file
15
core/modules/user/css/user.icons.theme.css
Normal file
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* @file
|
||||
* Styling for the user module icons.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Toolbar tab icon.
|
||||
*/
|
||||
.toolbar-bar .toolbar-icon-user:before {
|
||||
background-image: url(../../../misc/icons/bebebe/person.svg);
|
||||
}
|
||||
.toolbar-bar .toolbar-icon-user:active:before,
|
||||
.toolbar-bar .toolbar-icon-user.is-active:before {
|
||||
background-image: url(../../../misc/icons/ffffff/person.svg);
|
||||
}
|
21
core/modules/user/css/user.module.css
Normal file
21
core/modules/user/css/user.module.css
Normal file
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* @file
|
||||
* Module styling for user module.
|
||||
*/
|
||||
.password-strength__title,
|
||||
.password-strength__text {
|
||||
display: inline;
|
||||
}
|
||||
.password-strength__meter {
|
||||
height: 0.75em;
|
||||
margin-top: 0.5em;
|
||||
background-color: lightgray;
|
||||
}
|
||||
.password-strength__indicator {
|
||||
height: 100%;
|
||||
width: 0;
|
||||
background-color: gray;
|
||||
}
|
||||
.password-confirm-match {
|
||||
visibility: hidden;
|
||||
}
|
56
core/modules/user/css/user.theme.css
Normal file
56
core/modules/user/css/user.theme.css
Normal file
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* @file
|
||||
* Theme styling for user module.
|
||||
*/
|
||||
|
||||
/* Visual styling for the Password strength indicator */
|
||||
.password-strength__meter {
|
||||
margin-top: 0.5em;
|
||||
background-color: #ebeae4;
|
||||
}
|
||||
.password-strength__indicator {
|
||||
background-color: #77b259;
|
||||
-webkit-transition: width 0.5s ease-out;
|
||||
transition: width 0.5s ease-out;
|
||||
}
|
||||
.password-strength__indicator.is-weak {
|
||||
background-color: #e62600;
|
||||
}
|
||||
.password-strength__indicator.is-fair {
|
||||
background-color: #e09600;
|
||||
}
|
||||
.password-strength__indicator.is-good {
|
||||
background-color: #0074bd;
|
||||
}
|
||||
.password-strength__indicator.is-strong {
|
||||
background-color: #77b259;
|
||||
}
|
||||
|
||||
.password-confirm,
|
||||
.password-field,
|
||||
.password-strength,
|
||||
.password-confirm-match {
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
.password-suggestions {
|
||||
padding: 0.2em 0.5em;
|
||||
margin: 0.7em 0;
|
||||
max-width: 34.7em;
|
||||
border: 1px solid #b4b4b4;
|
||||
}
|
||||
.password-suggestions ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.confirm-parent,
|
||||
.password-parent {
|
||||
clear: left; /* LTR */
|
||||
margin: 0;
|
||||
max-width: 33em;
|
||||
overflow: hidden;
|
||||
}
|
||||
[dir="rtl"] .confirm-parent,
|
||||
[dir="rtl"] .password-parent {
|
||||
clear: right;
|
||||
}
|
BIN
core/modules/user/images/icon-user-active.png
Normal file
BIN
core/modules/user/images/icon-user-active.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 373 B |
BIN
core/modules/user/images/icon-user.png
Normal file
BIN
core/modules/user/images/icon-user.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 388 B |
37
core/modules/user/src/Access/LoginStatusCheck.php
Normal file
37
core/modules/user/src/Access/LoginStatusCheck.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Access\LoginStatusCheck.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Determines access to routes based on login status of current user.
|
||||
*/
|
||||
class LoginStatusCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* Checks access.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
* @param \Symfony\Component\Routing\Route $route
|
||||
* The route to check against.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(AccountInterface $account, Route $route) {
|
||||
$required_status = filter_var($route->getRequirement('_user_is_logged_in'), FILTER_VALIDATE_BOOLEAN);
|
||||
$actual_status = $account->isAuthenticated();
|
||||
return AccessResult::allowedIf($required_status === $actual_status)->addCacheContexts(['user.roles:authenticated']);
|
||||
}
|
||||
|
||||
}
|
50
core/modules/user/src/Access/PermissionAccessCheck.php
Normal file
50
core/modules/user/src/Access/PermissionAccessCheck.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Access\PermissionAccessCheck.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Determines access to routes based on permissions defined via
|
||||
* $module.permissions.yml files.
|
||||
*/
|
||||
class PermissionAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* Checks access.
|
||||
*
|
||||
* @param \Symfony\Component\Routing\Route $route
|
||||
* The route to check against.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(Route $route, AccountInterface $account) {
|
||||
$permission = $route->getRequirement('_permission');
|
||||
|
||||
if ($permission === NULL) {
|
||||
return AccessResult::neutral();
|
||||
}
|
||||
|
||||
// Allow to conjunct the permissions with OR ('+') or AND (',').
|
||||
$split = explode(',', $permission);
|
||||
if (count($split) > 1) {
|
||||
return AccessResult::allowedIfHasPermissions($account, $split, 'AND');
|
||||
}
|
||||
else {
|
||||
$split = explode('+', $permission);
|
||||
return AccessResult::allowedIfHasPermissions($account, $split, 'OR');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
32
core/modules/user/src/Access/RegisterAccessCheck.php
Normal file
32
core/modules/user/src/Access/RegisterAccessCheck.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Access\RegisterAccessCheck.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Access check for user registration routes.
|
||||
*/
|
||||
class RegisterAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* Checks access.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(AccountInterface $account) {
|
||||
$user_settings = \Drupal::config('user.settings');
|
||||
return AccessResult::allowedIf($account->isAnonymous() && $user_settings->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY)->cacheUntilConfigurationChanges($user_settings);
|
||||
}
|
||||
}
|
58
core/modules/user/src/Access/RoleAccessCheck.php
Normal file
58
core/modules/user/src/Access/RoleAccessCheck.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Access\RoleAccessCheck.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Access;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Routing\Access\AccessInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Determines access to routes based on roles.
|
||||
*
|
||||
* You can specify the '_role' key on route requirements. If you specify a
|
||||
* single role, users with that role with have access. If you specify multiple
|
||||
* ones you can conjunct them with AND by using a "," and with OR by using "+".
|
||||
*/
|
||||
class RoleAccessCheck implements AccessInterface {
|
||||
|
||||
/**
|
||||
* Checks access.
|
||||
*
|
||||
* @param \Symfony\Component\Routing\Route $route
|
||||
* The route to check against.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The currently logged in account.
|
||||
*
|
||||
* @return \Drupal\Core\Access\AccessResultInterface
|
||||
* The access result.
|
||||
*/
|
||||
public function access(Route $route, AccountInterface $account) {
|
||||
// Requirements just allow strings, so this might be a comma separated list.
|
||||
$rid_string = $route->getRequirement('_role');
|
||||
|
||||
$explode_and = array_filter(array_map('trim', explode(',', $rid_string)));
|
||||
if (count($explode_and) > 1) {
|
||||
$diff = array_diff($explode_and, $account->getRoles());
|
||||
if (empty($diff)) {
|
||||
return AccessResult::allowed()->addCacheContexts(['user.roles']);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$explode_or = array_filter(array_map('trim', explode('+', $rid_string)));
|
||||
$intersection = array_intersect($explode_or, $account->getRoles());
|
||||
if (!empty($intersection)) {
|
||||
return AccessResult::allowed()->addCacheContexts(['user.roles']);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no allowed role, give other access checks a chance.
|
||||
return AccessResult::neutral()->addCacheContexts(['user.roles']);
|
||||
}
|
||||
|
||||
}
|
410
core/modules/user/src/AccountForm.php
Normal file
410
core/modules/user/src/AccountForm.php
Normal file
|
@ -0,0 +1,410 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\AccountForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Entity\ContentEntityForm;
|
||||
use Drupal\Core\Entity\EntityConstraintViolationListInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\Query\QueryFactory;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\language\ConfigurableLanguageManagerInterface;
|
||||
use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser;
|
||||
use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Form controller for the user account forms.
|
||||
*/
|
||||
abstract class AccountForm extends ContentEntityForm {
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* The entity query factory service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\Query\QueryFactory
|
||||
*/
|
||||
protected $entityQuery;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
* @param \Drupal\Core\Entity\Query\QueryFactory $entity_query
|
||||
* The entity query factory.
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager, QueryFactory $entity_query) {
|
||||
parent::__construct($entity_manager);
|
||||
$this->languageManager = $language_manager;
|
||||
$this->entityQuery = $entity_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('entity.query')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
/** @var \Drupal\user\UserInterface $account */
|
||||
$account = $this->entity;
|
||||
$user = $this->currentUser();
|
||||
$config = \Drupal::config('user.settings');
|
||||
$form['#cache']['tags'] = $config->getCacheTags();
|
||||
|
||||
$language_interface = \Drupal::languageManager()->getCurrentLanguage();
|
||||
$register = $account->isAnonymous();
|
||||
$admin = $user->hasPermission('administer users');
|
||||
|
||||
// Account information.
|
||||
$form['account'] = array(
|
||||
'#type' => 'container',
|
||||
'#weight' => -10,
|
||||
);
|
||||
|
||||
// The mail field is NOT required if account originally had no mail set
|
||||
// and the user performing the edit has 'administer users' permission.
|
||||
// This allows users without email address to be edited and deleted.
|
||||
// Also see \Drupal\user\Plugin\Validation\Constraint\UserMailRequired.
|
||||
$form['account']['mail'] = array(
|
||||
'#type' => 'email',
|
||||
'#title' => $this->t('Email address'),
|
||||
'#description' => $this->t('A valid email address. All emails from the system will be sent to this address. The email address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by email.'),
|
||||
'#required' => !(!$account->getEmail() && $user->hasPermission('administer users')),
|
||||
'#default_value' => (!$register ? $account->getEmail() : ''),
|
||||
);
|
||||
|
||||
// Only show name field on registration form or user can change own username.
|
||||
$form['account']['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Username'),
|
||||
'#maxlength' => USERNAME_MAX_LENGTH,
|
||||
'#description' => $this->t('Spaces are allowed; punctuation is not allowed except for periods, hyphens, apostrophes, and underscores.'),
|
||||
'#required' => TRUE,
|
||||
'#attributes' => array(
|
||||
'class' => array('username'),
|
||||
'autocorrect' => 'off',
|
||||
'autocapitalize' => 'off',
|
||||
'spellcheck' => 'false',
|
||||
),
|
||||
'#default_value' => (!$register ? $account->getUsername() : ''),
|
||||
'#access' => ($register || ($user->id() == $account->id() && $user->hasPermission('change own username')) || $admin),
|
||||
);
|
||||
|
||||
// Display password field only for existing users or when user is allowed to
|
||||
// assign a password during registration.
|
||||
if (!$register) {
|
||||
$form['account']['pass'] = array(
|
||||
'#type' => 'password_confirm',
|
||||
'#size' => 25,
|
||||
'#description' => $this->t('To change the current user password, enter the new password in both fields.'),
|
||||
);
|
||||
|
||||
// To skip the current password field, the user must have logged in via a
|
||||
// one-time link and have the token in the URL. Store this in $form_state
|
||||
// so it persists even on subsequent Ajax requests.
|
||||
if (!$form_state->get('user_pass_reset')) {
|
||||
$user_pass_reset = $pass_reset = isset($_SESSION['pass_reset_' . $account->id()]) && (\Drupal::request()->query->get('pass-reset-token') == $_SESSION['pass_reset_' . $account->id()]);
|
||||
$form_state->set('user_pass_reset', $user_pass_reset);
|
||||
}
|
||||
|
||||
$protected_values = array();
|
||||
$current_pass_description = '';
|
||||
|
||||
// The user may only change their own password without their current
|
||||
// password if they logged in via a one-time login link.
|
||||
if (!$form_state->get('user_pass_reset')) {
|
||||
$protected_values['mail'] = $form['account']['mail']['#title'];
|
||||
$protected_values['pass'] = $this->t('Password');
|
||||
$request_new = $this->l($this->t('Reset your password'), new Url('user.pass',
|
||||
array(), array('attributes' => array('title' => $this->t('Send password reset instructions via e-mail.'))))
|
||||
);
|
||||
$current_pass_description = $this->t('Required if you want to change the %mail or %pass below. !request_new.',
|
||||
array(
|
||||
'%mail' => $protected_values['mail'],
|
||||
'%pass' => $protected_values['pass'],
|
||||
'!request_new' => $request_new,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// The user must enter their current password to change to a new one.
|
||||
if ($user->id() == $account->id()) {
|
||||
$form['account']['current_pass'] = array(
|
||||
'#type' => 'password',
|
||||
'#title' => $this->t('Current password'),
|
||||
'#size' => 25,
|
||||
'#access' => !empty($protected_values),
|
||||
'#description' => $current_pass_description,
|
||||
'#weight' => -5,
|
||||
// Do not let web browsers remember this password, since we are
|
||||
// trying to confirm that the person submitting the form actually
|
||||
// knows the current one.
|
||||
'#attributes' => array('autocomplete' => 'off'),
|
||||
);
|
||||
|
||||
$form_state->set('user', $account);
|
||||
}
|
||||
}
|
||||
elseif (!$config->get('verify_mail') || $admin) {
|
||||
$form['account']['pass'] = array(
|
||||
'#type' => 'password_confirm',
|
||||
'#size' => 25,
|
||||
'#description' => $this->t('Provide a password for the new account in both fields.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
}
|
||||
|
||||
// When not building the user registration form, prevent web browsers from
|
||||
// autofilling/prefilling the email, username, and password fields.
|
||||
if ($this->getOperation() != 'register') {
|
||||
foreach (array('mail', 'name', 'pass') as $key) {
|
||||
if (isset($form['account'][$key])) {
|
||||
$form['account'][$key]['#attributes']['autocomplete'] = 'off';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($admin) {
|
||||
$status = $account->isActive();
|
||||
}
|
||||
else {
|
||||
$status = $register ? $config->get('register') == USER_REGISTER_VISITORS : $account->isActive();
|
||||
}
|
||||
|
||||
$form['account']['status'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Status'),
|
||||
'#default_value' => $status,
|
||||
'#options' => array($this->t('Blocked'), $this->t('Active')),
|
||||
'#access' => $admin,
|
||||
);
|
||||
|
||||
$roles = array_map(array('\Drupal\Component\Utility\SafeMarkup', 'checkPlain'), user_role_names(TRUE));
|
||||
|
||||
$form['account']['roles'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Roles'),
|
||||
'#default_value' => (!$register ? $account->getRoles() : array()),
|
||||
'#options' => $roles,
|
||||
'#access' => $roles && $user->hasPermission('administer permissions'),
|
||||
);
|
||||
|
||||
// Special handling for the inevitable "Authenticated user" role.
|
||||
$form['account']['roles'][RoleInterface::AUTHENTICATED_ID] = array(
|
||||
'#default_value' => TRUE,
|
||||
'#disabled' => TRUE,
|
||||
);
|
||||
|
||||
$form['account']['notify'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Notify user of new account'),
|
||||
'#access' => $register && $admin,
|
||||
);
|
||||
|
||||
$user_preferred_langcode = $register ? $language_interface->getId() : $account->getPreferredLangcode();
|
||||
|
||||
$user_preferred_admin_langcode = $register ? $language_interface->getId() : $account->getPreferredAdminLangcode(FALSE);
|
||||
|
||||
// Is the user preferred language added?
|
||||
$user_language_added = FALSE;
|
||||
if ($this->languageManager instanceof ConfigurableLanguageManagerInterface) {
|
||||
$negotiator = $this->languageManager->getNegotiator();
|
||||
$user_language_added = $negotiator && $negotiator->isNegotiationMethodEnabled(LanguageNegotiationUser::METHOD_ID, LanguageInterface::TYPE_INTERFACE);
|
||||
}
|
||||
$form['language'] = array(
|
||||
'#type' => $this->languageManager->isMultilingual() ? 'details' : 'container',
|
||||
'#title' => $this->t('Language settings'),
|
||||
'#open' => TRUE,
|
||||
// Display language selector when either creating a user on the admin
|
||||
// interface or editing a user account.
|
||||
'#access' => !$register || $user->hasPermission('administer users'),
|
||||
);
|
||||
|
||||
$form['language']['preferred_langcode'] = array(
|
||||
'#type' => 'language_select',
|
||||
'#title' => $this->t('Site language'),
|
||||
'#languages' => LanguageInterface::STATE_CONFIGURABLE,
|
||||
'#default_value' => $user_preferred_langcode,
|
||||
'#description' => $user_language_added ? $this->t("This account's preferred language for emails and site presentation.") : $this->t("This account's preferred language for emails."),
|
||||
// This is used to explain that user preferred language and entity
|
||||
// language are synchronized. It can be removed if a different behavior is
|
||||
// desired.
|
||||
'#pre_render' => ['user_langcode' => [$this, 'alterPreferredLangcodeDescription']],
|
||||
);
|
||||
|
||||
// Only show the account setting for Administration pages language to users
|
||||
// if one of the detection and selection methods uses it.
|
||||
$show_admin_language = FALSE;
|
||||
if ($account->hasPermission('access administration pages') && $this->languageManager instanceof ConfigurableLanguageManagerInterface) {
|
||||
$negotiator = $this->languageManager->getNegotiator();
|
||||
$show_admin_language = $negotiator && $negotiator->isNegotiationMethodEnabled(LanguageNegotiationUserAdmin::METHOD_ID);
|
||||
}
|
||||
$form['language']['preferred_admin_langcode'] = array(
|
||||
'#type' => 'language_select',
|
||||
'#title' => $this->t('Administration pages language'),
|
||||
'#languages' => LanguageInterface::STATE_CONFIGURABLE,
|
||||
'#default_value' => $user_preferred_admin_langcode,
|
||||
'#access' => $show_admin_language,
|
||||
'#empty_option' => $this->t('- No preference -'),
|
||||
'#empty_value' => '',
|
||||
);
|
||||
|
||||
// User entities contain both a langcode property (for identifying the
|
||||
// language of the entity data) and a preferred_langcode property (see
|
||||
// above). Rather than provide a UI forcing the user to choose both
|
||||
// separately, assume that the user profile data is in the user's preferred
|
||||
// language. This entity builder provides that synchronization. For
|
||||
// use-cases where this synchronization is not desired, a module can alter
|
||||
// or remove this item.
|
||||
$form['#entity_builders']['sync_user_langcode'] = [$this, 'syncUserLangcode'];
|
||||
|
||||
return parent::form($form, $form_state, $account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters the preferred language widget description.
|
||||
*
|
||||
* @param array $element
|
||||
* The preferred language form element.
|
||||
*
|
||||
* @return array
|
||||
* The preferred language form element.
|
||||
*/
|
||||
public function alterPreferredLangcodeDescription(array $element) {
|
||||
// Only add to the description if the form element has a description.
|
||||
if (isset($element['#description'])) {
|
||||
$element['#description'] .= ' ' . $this->t("This is also assumed to be the primary language of this account's profile information.");
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes preferred language and entity language.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type identifier.
|
||||
* @param \Drupal\user\UserInterface $user
|
||||
* The entity updated with the submitted values.
|
||||
* @param array $form
|
||||
* The complete form array.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*/
|
||||
public function syncUserLangcode($entity_type_id, UserInterface $user, array &$form, FormStateInterface &$form_state) {
|
||||
$user->getUntranslated()->langcode = $user->preferred_langcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildEntity(array $form, FormStateInterface $form_state) {
|
||||
// Change the roles array to a list of enabled roles.
|
||||
// @todo: Alter the form state as the form values are directly extracted and
|
||||
// set on the field, which throws an exception as the list requires
|
||||
// numeric keys. Allow to override this per field. As this function is
|
||||
// called twice, we have to prevent it from getting the array keys twice.
|
||||
|
||||
if (is_string(key($form_state->getValue('roles')))) {
|
||||
$form_state->setValue('roles', array_keys(array_filter($form_state->getValue('roles'))));
|
||||
}
|
||||
|
||||
/** @var \Drupal\user\UserInterface $account */
|
||||
$account = parent::buildEntity($form, $form_state);
|
||||
|
||||
// Translate the empty value '' of language selects to an unset field.
|
||||
foreach (array('preferred_langcode', 'preferred_admin_langcode') as $field_name) {
|
||||
if ($form_state->getValue($field_name) === '') {
|
||||
$account->$field_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Set existing password if set in the form state.
|
||||
if ($current_pass = $form_state->getValue('current_pass')) {
|
||||
$account->setExistingPassword($current_pass);
|
||||
}
|
||||
|
||||
// Skip the protected user field constraint if the user came from the
|
||||
// password recovery page.
|
||||
$account->_skipProtectedUserFieldConstraint = $form_state->get('user_pass_reset');
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditedFieldNames(FormStateInterface $form_state) {
|
||||
return array_merge(array(
|
||||
'name',
|
||||
'pass',
|
||||
'mail',
|
||||
'timezone',
|
||||
'langcode',
|
||||
'preferred_langcode',
|
||||
'preferred_admin_langcode'
|
||||
), parent::getEditedFieldNames($form_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function flagViolations(EntityConstraintViolationListInterface $violations, array $form, FormStateInterface $form_state) {
|
||||
// Manually flag violations of fields not handled by the form display. This
|
||||
// is necessary as entity form displays only flag violations for fields
|
||||
// contained in the display.
|
||||
$field_names = array(
|
||||
'name',
|
||||
'pass',
|
||||
'mail',
|
||||
'timezone',
|
||||
'langcode',
|
||||
'preferred_langcode',
|
||||
'preferred_admin_langcode'
|
||||
);
|
||||
foreach ($violations->getByFields($field_names) as $violation) {
|
||||
list($field_name) = explode('.', $violation->getPropertyPath(), 2);
|
||||
$form_state->setErrorByName($field_name, $violation->getMessage());
|
||||
}
|
||||
parent::flagViolations($violations, $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
$user = $this->getEntity($form_state);
|
||||
// If there's a session set to the users id, remove the password reset tag
|
||||
// since a new password was saved.
|
||||
if (isset($_SESSION['pass_reset_'. $user->id()])) {
|
||||
unset($_SESSION['pass_reset_'. $user->id()]);
|
||||
}
|
||||
}
|
||||
}
|
482
core/modules/user/src/AccountSettingsForm.php
Normal file
482
core/modules/user/src/AccountSettingsForm.php
Normal file
|
@ -0,0 +1,482 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\AccountSettingsForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure user settings for this site.
|
||||
*/
|
||||
class AccountSettingsForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The role storage used when changing the admin role.
|
||||
*
|
||||
* @var \Drupal\user\RoleStorageInterface
|
||||
*/
|
||||
protected $roleStorage;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\user\AccountSettingsForm object.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The factory for configuration objects.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\user\RoleStorageInterface $role_storage
|
||||
* The role storage.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, RoleStorageInterface $role_storage) {
|
||||
parent::__construct($config_factory);
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->roleStorage = $role_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('entity.manager')->getStorage('user_role')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'user_admin_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return [
|
||||
'system.site',
|
||||
'user.mail',
|
||||
'user.settings',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
$config = $this->config('user.settings');
|
||||
$mail_config = $this->config('user.mail');
|
||||
$site_config = $this->config('system.site');
|
||||
|
||||
$form['#attached']['library'][] = 'user/drupal.user.admin';
|
||||
|
||||
// Settings for anonymous users.
|
||||
$form['anonymous_settings'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Anonymous users'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
$form['anonymous_settings']['anonymous'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Name'),
|
||||
'#default_value' => $config->get('anonymous'),
|
||||
'#description' => $this->t('The name used to indicate anonymous users.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
// Administrative role option.
|
||||
$form['admin_role'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Administrator role'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
// Do not allow users to set the anonymous or authenticated user roles as the
|
||||
// administrator role.
|
||||
$roles = user_role_names(TRUE);
|
||||
unset($roles[RoleInterface::AUTHENTICATED_ID]);
|
||||
|
||||
$admin_roles = $this->roleStorage->getQuery()
|
||||
->condition('is_admin', TRUE)
|
||||
->execute();
|
||||
$default_value = reset($admin_roles);
|
||||
|
||||
$form['admin_role']['user_admin_role'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Administrator role'),
|
||||
'#empty_value' => '',
|
||||
'#default_value' => $default_value,
|
||||
'#options' => $roles,
|
||||
'#description' => $this->t('This role will be automatically assigned new permissions whenever a module is enabled. Changing this setting will not affect existing permissions.'),
|
||||
// Don't allow to select a single admin role in case multiple roles got
|
||||
// marked as admin role already.
|
||||
'#access' => count($admin_roles) <= 1,
|
||||
);
|
||||
|
||||
// @todo Remove this check once language settings are generalized.
|
||||
if ($this->moduleHandler->moduleExists('content_translation')) {
|
||||
$form['language'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Language settings'),
|
||||
'#open' => TRUE,
|
||||
'#tree' => TRUE,
|
||||
);
|
||||
$form_state->set(['content_translation', 'key'], 'language');
|
||||
$form['language'] += content_translation_enable_widget('user', 'user', $form, $form_state);
|
||||
}
|
||||
|
||||
// User registration settings.
|
||||
$form['registration_cancellation'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Registration and cancellation'),
|
||||
'#open' => TRUE,
|
||||
);
|
||||
$form['registration_cancellation']['user_register'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Who can register accounts?'),
|
||||
'#default_value' => $config->get('register'),
|
||||
'#options' => array(
|
||||
USER_REGISTER_ADMINISTRATORS_ONLY => $this->t('Administrators only'),
|
||||
USER_REGISTER_VISITORS => $this->t('Visitors'),
|
||||
USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL => $this->t('Visitors, but administrator approval is required'),
|
||||
)
|
||||
);
|
||||
$form['registration_cancellation']['user_email_verification'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Require email verification when a visitor creates an account'),
|
||||
'#default_value' => $config->get('verify_mail'),
|
||||
'#description' => $this->t('New users will be required to validate their email address prior to logging into the site, and will be assigned a system-generated password. With this setting disabled, users will be logged in immediately upon registering, and may select their own passwords during registration.')
|
||||
);
|
||||
$form['registration_cancellation']['user_password_strength'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Enable password strength indicator'),
|
||||
'#default_value' => $config->get('password_strength'),
|
||||
);
|
||||
$form['registration_cancellation']['user_cancel_method'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('When cancelling a user account'),
|
||||
'#default_value' => $config->get('cancel_method'),
|
||||
'#description' => $this->t('Users with the %select-cancel-method or %administer-users <a href="@permissions-url">permissions</a> can override this default method.', array('%select-cancel-method' => $this->t('Select method for cancelling account'), '%administer-users' => $this->t('Administer users'), '@permissions-url' => $this->url('user.admin_permissions'))),
|
||||
);
|
||||
$form['registration_cancellation']['user_cancel_method'] += user_cancel_methods();
|
||||
foreach (Element::children($form['registration_cancellation']['user_cancel_method']) as $key) {
|
||||
// All account cancellation methods that specify #access cannot be
|
||||
// configured as default method.
|
||||
// @see hook_user_cancel_methods_alter()
|
||||
if (isset($form['registration_cancellation']['user_cancel_method'][$key]['#access'])) {
|
||||
$form['registration_cancellation']['user_cancel_method'][$key]['#access'] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// Default notifications address.
|
||||
$form['mail_notification_address'] = array(
|
||||
'#type' => 'email',
|
||||
'#title' => $this->t('Notification email address'),
|
||||
'#default_value' => $site_config->get('mail_notification'),
|
||||
'#description' => $this->t("The email address to be used as the 'from' address for all account notifications listed below. If <em>'Visitors, but administrator approval is required'</em> is selected above, a notification email will also be sent to this address for any new registrations. Leave empty to use the default system email address <em>(%site-email).</em>", array('%site-email' => $site_config->get('mail'))),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
|
||||
$form['email'] = array(
|
||||
'#type' => 'vertical_tabs',
|
||||
'#title' => $this->t('Emails'),
|
||||
);
|
||||
// These email tokens are shared for all settings, so just define
|
||||
// the list once to help ensure they stay in sync.
|
||||
$email_token_help = $this->t('Available variables are: [site:name], [site:url], [user:name], [user:mail], [site:login-url], [site:url-brief], [user:edit-url], [user:one-time-login-url], [user:cancel-url].');
|
||||
|
||||
$form['email_admin_created'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Welcome (new user created by administrator)'),
|
||||
'#open' => $config->get('register') == USER_REGISTER_ADMINISTRATORS_ONLY,
|
||||
'#description' => $this->t('Edit the welcome email messages sent to new member accounts created by an administrator.') . ' ' . $email_token_help,
|
||||
'#group' => 'email',
|
||||
);
|
||||
$form['email_admin_created']['user_mail_register_admin_created_subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Subject'),
|
||||
'#default_value' => $mail_config->get('register_admin_created.subject'),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
$form['email_admin_created']['user_mail_register_admin_created_body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Body'),
|
||||
'#default_value' => $mail_config->get('register_admin_created.body'),
|
||||
'#rows' => 15,
|
||||
);
|
||||
|
||||
$form['email_pending_approval'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Welcome (awaiting approval)'),
|
||||
'#open' => $config->get('register') == USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL,
|
||||
'#description' => $this->t('Edit the welcome email messages sent to new members upon registering, when administrative approval is required.') . ' ' . $email_token_help,
|
||||
'#group' => 'email',
|
||||
);
|
||||
$form['email_pending_approval']['user_mail_register_pending_approval_subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Subject'),
|
||||
'#default_value' => $mail_config->get('register_pending_approval.subject'),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
$form['email_pending_approval']['user_mail_register_pending_approval_body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Body'),
|
||||
'#default_value' => $mail_config->get('register_pending_approval.body'),
|
||||
'#rows' => 8,
|
||||
);
|
||||
|
||||
$form['email_pending_approval_admin'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Admin (user awaiting approval)'),
|
||||
'#open' => $config->get('register') == USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL,
|
||||
'#description' => $this->t('Edit the email notifying the site administrator that there are new members awaiting administrative approval.') . ' ' . $email_token_help,
|
||||
'#group' => 'email',
|
||||
);
|
||||
$form['email_pending_approval_admin']['register_pending_approval_admin_subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Subject'),
|
||||
'#default_value' => $mail_config->get('register_pending_approval_admin.subject'),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
$form['email_pending_approval_admin']['register_pending_approval_admin_body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Body'),
|
||||
'#default_value' => $mail_config->get('register_pending_approval_admin.body'),
|
||||
'#rows' => 8,
|
||||
);
|
||||
|
||||
$form['email_no_approval_required'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Welcome (no approval required)'),
|
||||
'#open' => $config->get('register') == USER_REGISTER_VISITORS,
|
||||
'#description' => $this->t('Edit the welcome email messages sent to new members upon registering, when no administrator approval is required.') . ' ' . $email_token_help,
|
||||
'#group' => 'email',
|
||||
);
|
||||
$form['email_no_approval_required']['user_mail_register_no_approval_required_subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Subject'),
|
||||
'#default_value' => $mail_config->get('register_no_approval_required.subject'),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
$form['email_no_approval_required']['user_mail_register_no_approval_required_body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Body'),
|
||||
'#default_value' => $mail_config->get('register_no_approval_required.body'),
|
||||
'#rows' => 15,
|
||||
);
|
||||
|
||||
$form['email_password_reset'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Password recovery'),
|
||||
'#description' => $this->t('Edit the email messages sent to users who request a new password.') . ' ' . $email_token_help,
|
||||
'#group' => 'email',
|
||||
'#weight' => 10,
|
||||
);
|
||||
$form['email_password_reset']['user_mail_password_reset_subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Subject'),
|
||||
'#default_value' => $mail_config->get('password_reset.subject'),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
$form['email_password_reset']['user_mail_password_reset_body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Body'),
|
||||
'#default_value' => $mail_config->get('password_reset.body'),
|
||||
'#rows' => 12,
|
||||
);
|
||||
|
||||
$form['email_activated'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Account activation'),
|
||||
'#description' => $this->t('Enable and edit email messages sent to users upon account activation (when an administrator activates an account of a user who has already registered, on a site where administrative approval is required).') . ' ' . $email_token_help,
|
||||
'#group' => 'email',
|
||||
);
|
||||
$form['email_activated']['user_mail_status_activated_notify'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Notify user when account is activated'),
|
||||
'#default_value' => $config->get('notify.status_activated'),
|
||||
);
|
||||
$form['email_activated']['settings'] = array(
|
||||
'#type' => 'container',
|
||||
'#states' => array(
|
||||
// Hide the additional settings when this email is disabled.
|
||||
'invisible' => array(
|
||||
'input[name="user_mail_status_activated_notify"]' => array('checked' => FALSE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['email_activated']['settings']['user_mail_status_activated_subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Subject'),
|
||||
'#default_value' => $mail_config->get('status_activated.subject'),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
$form['email_activated']['settings']['user_mail_status_activated_body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Body'),
|
||||
'#default_value' => $mail_config->get('status_activated.body'),
|
||||
'#rows' => 15,
|
||||
);
|
||||
|
||||
$form['email_blocked'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Account blocked'),
|
||||
'#description' => $this->t('Enable and edit email messages sent to users when their accounts are blocked.') . ' ' . $email_token_help,
|
||||
'#group' => 'email',
|
||||
);
|
||||
$form['email_blocked']['user_mail_status_blocked_notify'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Notify user when account is blocked'),
|
||||
'#default_value' => $config->get('notify.status_blocked'),
|
||||
);
|
||||
$form['email_blocked']['settings'] = array(
|
||||
'#type' => 'container',
|
||||
'#states' => array(
|
||||
// Hide the additional settings when the blocked email is disabled.
|
||||
'invisible' => array(
|
||||
'input[name="user_mail_status_blocked_notify"]' => array('checked' => FALSE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['email_blocked']['settings']['user_mail_status_blocked_subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Subject'),
|
||||
'#default_value' => $mail_config->get('status_blocked.subject'),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
$form['email_blocked']['settings']['user_mail_status_blocked_body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Body'),
|
||||
'#default_value' => $mail_config->get('status_blocked.body'),
|
||||
'#rows' => 3,
|
||||
);
|
||||
|
||||
$form['email_cancel_confirm'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Account cancellation confirmation'),
|
||||
'#description' => $this->t('Edit the email messages sent to users when they attempt to cancel their accounts.') . ' ' . $email_token_help,
|
||||
'#group' => 'email',
|
||||
);
|
||||
$form['email_cancel_confirm']['user_mail_cancel_confirm_subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Subject'),
|
||||
'#default_value' => $mail_config->get('cancel_confirm.subject'),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
$form['email_cancel_confirm']['user_mail_cancel_confirm_body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Body'),
|
||||
'#default_value' => $mail_config->get('cancel_confirm.body'),
|
||||
'#rows' => 3,
|
||||
);
|
||||
|
||||
$form['email_canceled'] = array(
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Account canceled'),
|
||||
'#description' => $this->t('Enable and edit email messages sent to users when their accounts are canceled.') . ' ' . $email_token_help,
|
||||
'#group' => 'email',
|
||||
);
|
||||
$form['email_canceled']['user_mail_status_canceled_notify'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Notify user when account is canceled'),
|
||||
'#default_value' => $config->get('notify.status_canceled'),
|
||||
);
|
||||
$form['email_canceled']['settings'] = array(
|
||||
'#type' => 'container',
|
||||
'#states' => array(
|
||||
// Hide the settings when the cancel notify checkbox is disabled.
|
||||
'invisible' => array(
|
||||
'input[name="user_mail_status_canceled_notify"]' => array('checked' => FALSE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['email_canceled']['settings']['user_mail_status_canceled_subject'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Subject'),
|
||||
'#default_value' => $mail_config->get('status_canceled.subject'),
|
||||
'#maxlength' => 180,
|
||||
);
|
||||
$form['email_canceled']['settings']['user_mail_status_canceled_body'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Body'),
|
||||
'#default_value' => $mail_config->get('status_canceled.body'),
|
||||
'#rows' => 3,
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
$this->config('user.settings')
|
||||
->set('anonymous', $form_state->getValue('anonymous'))
|
||||
->set('register', $form_state->getValue('user_register'))
|
||||
->set('password_strength', $form_state->getValue('user_password_strength'))
|
||||
->set('verify_mail', $form_state->getValue('user_email_verification'))
|
||||
->set('cancel_method', $form_state->getValue('user_cancel_method'))
|
||||
->set('notify.status_activated', $form_state->getValue('user_mail_status_activated_notify'))
|
||||
->set('notify.status_blocked', $form_state->getValue('user_mail_status_blocked_notify'))
|
||||
->set('notify.status_canceled', $form_state->getValue('user_mail_status_canceled_notify'))
|
||||
->save();
|
||||
$this->config('user.mail')
|
||||
->set('cancel_confirm.body', $form_state->getValue('user_mail_cancel_confirm_body'))
|
||||
->set('cancel_confirm.subject', $form_state->getValue('user_mail_cancel_confirm_subject'))
|
||||
->set('password_reset.body', $form_state->getValue('user_mail_password_reset_body'))
|
||||
->set('password_reset.subject', $form_state->getValue('user_mail_password_reset_subject'))
|
||||
->set('register_admin_created.body', $form_state->getValue('user_mail_register_admin_created_body'))
|
||||
->set('register_admin_created.subject', $form_state->getValue('user_mail_register_admin_created_subject'))
|
||||
->set('register_no_approval_required.body', $form_state->getValue('user_mail_register_no_approval_required_body'))
|
||||
->set('register_no_approval_required.subject', $form_state->getValue('user_mail_register_no_approval_required_subject'))
|
||||
->set('register_pending_approval.body', $form_state->getValue('user_mail_register_pending_approval_body'))
|
||||
->set('register_pending_approval.subject', $form_state->getValue('user_mail_register_pending_approval_subject'))
|
||||
->set('status_activated.body', $form_state->getValue('user_mail_status_activated_body'))
|
||||
->set('status_activated.subject', $form_state->getValue('user_mail_status_activated_subject'))
|
||||
->set('status_blocked.body', $form_state->getValue('user_mail_status_blocked_body'))
|
||||
->set('status_blocked.subject', $form_state->getValue('user_mail_status_blocked_subject'))
|
||||
->set('status_canceled.body', $form_state->getValue('user_mail_status_canceled_body'))
|
||||
->set('status_canceled.subject', $form_state->getValue('user_mail_status_canceled_subject'))
|
||||
->save();
|
||||
$this->config('system.site')
|
||||
->set('mail_notification', $form_state->getValue('mail_notification_address'))
|
||||
->save();
|
||||
|
||||
// Change the admin role.
|
||||
if ($form_state->hasValue('user_admin_role')) {
|
||||
$admin_roles = $this->roleStorage->getQuery()
|
||||
->condition('is_admin', TRUE)
|
||||
->execute();
|
||||
|
||||
foreach ($admin_roles as $rid) {
|
||||
$this->roleStorage->load($rid)->setIsAdmin(FALSE)->save();
|
||||
}
|
||||
|
||||
$new_admin_role = $form_state->getValue('user_admin_role');
|
||||
if ($new_admin_role) {
|
||||
$this->roleStorage->load($new_admin_role)->setIsAdmin(TRUE)->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
98
core/modules/user/src/Authentication/Provider/Cookie.php
Normal file
98
core/modules/user/src/Authentication/Provider/Cookie.php
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Authentication\Provider\Cookie.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Authentication\Provider;
|
||||
|
||||
use Drupal\Core\Authentication\AuthenticationProviderInterface;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Session\UserSession;
|
||||
use Drupal\Core\Session\SessionConfigurationInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
/**
|
||||
* Cookie based authentication provider.
|
||||
*/
|
||||
class Cookie implements AuthenticationProviderInterface {
|
||||
|
||||
/**
|
||||
* The session configuration.
|
||||
*
|
||||
* @var \Drupal\Core\Session\SessionConfigurationInterface
|
||||
*/
|
||||
protected $sessionConfiguration;
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* Constructs a new cookie authentication provider.
|
||||
*
|
||||
* @param \Drupal\Core\Session\SessionConfigurationInterface $session_configuration
|
||||
* The session configuration.
|
||||
* @param \Drupal\Core\Database\Connection $connection
|
||||
* The database connection.
|
||||
*/
|
||||
public function __construct(SessionConfigurationInterface $session_configuration, Connection $connection) {
|
||||
$this->sessionConfiguration = $session_configuration;
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies(Request $request) {
|
||||
return $request->hasSession() && $this->sessionConfiguration->hasSession($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate(Request $request) {
|
||||
return $this->getUserFromSession($request->getSession());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UserSession object for the given session.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Session\SessionInterface $session
|
||||
* The session.
|
||||
*
|
||||
* @return \Drupal\Core\Session\AccountInterface|NULL
|
||||
* The UserSession object for the current user, or NULL if this is an
|
||||
* anonymous session.
|
||||
*/
|
||||
protected function getUserFromSession(SessionInterface $session) {
|
||||
if ($uid = $session->get('uid')) {
|
||||
// @todo Load the User entity in SessionHandler so we don't need queries.
|
||||
// @see https://www.drupal.org/node/2345611
|
||||
$values = $this->connection
|
||||
->query('SELECT * FROM {users_field_data} u WHERE u.uid = :uid AND u.default_langcode = 1', [':uid' => $uid])
|
||||
->fetchAssoc();
|
||||
|
||||
// Check if the user data was found and the user is active.
|
||||
if (!empty($values) && $values['status'] == 1) {
|
||||
// Add the user's roles.
|
||||
$rids = $this->connection
|
||||
->query('SELECT roles_target_id FROM {user__roles} WHERE entity_id = :uid', [':uid' => $values['uid']])
|
||||
->fetchCol();
|
||||
$values['roles'] = array_merge([AccountInterface::AUTHENTICATED_ROLE], $rids);
|
||||
|
||||
return new UserSession($values);
|
||||
}
|
||||
}
|
||||
|
||||
// This is an anonymous session.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
218
core/modules/user/src/Controller/UserController.php
Normal file
218
core/modules/user/src/Controller/UserController.php
Normal file
|
@ -0,0 +1,218 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Controller\UserController.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Controller;
|
||||
|
||||
use Drupal\Component\Utility\Xss;
|
||||
use Drupal\Core\Controller\ControllerBase;
|
||||
use Drupal\Core\Datetime\DateFormatter;
|
||||
use Drupal\user\UserDataInterface;
|
||||
use Drupal\user\UserInterface;
|
||||
use Drupal\user\UserStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
|
||||
/**
|
||||
* Controller routines for user routes.
|
||||
*/
|
||||
class UserController extends ControllerBase {
|
||||
|
||||
/**
|
||||
* The date formatter service.
|
||||
*
|
||||
* @var \Drupal\Core\Datetime\DateFormatter
|
||||
*/
|
||||
protected $dateFormatter;
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\user\UserStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* The user data service.
|
||||
*
|
||||
* @var \Drupal\user\UserDataInterface
|
||||
*/
|
||||
protected $userData;
|
||||
|
||||
/**
|
||||
* Constructs a UserController object.
|
||||
*
|
||||
* @param \Drupal\Core\Datetime\DateFormatter $date_formatter
|
||||
* The date formatter service.
|
||||
* @param \Drupal\user\UserStorageInterface $user_storage
|
||||
* The user storage.
|
||||
* @param \Drupal\user\UserDataInterface $user_data
|
||||
* The user data service.
|
||||
*/
|
||||
public function __construct(DateFormatter $date_formatter, UserStorageInterface $user_storage, UserDataInterface $user_data) {
|
||||
$this->dateFormatter = $date_formatter;
|
||||
$this->userStorage = $user_storage;
|
||||
$this->userData = $user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('date.formatter'),
|
||||
$container->get('entity.manager')->getStorage('user'),
|
||||
$container->get('user.data')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user password reset page.
|
||||
*
|
||||
* @param int $uid
|
||||
* UID of user requesting reset.
|
||||
* @param int $timestamp
|
||||
* The current timestamp.
|
||||
* @param string $hash
|
||||
* Login link hash.
|
||||
*
|
||||
* @return array|\Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* The form structure or a redirect response.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* If the login link is for a blocked user or invalid user ID.
|
||||
*/
|
||||
public function resetPass($uid, $timestamp, $hash) {
|
||||
$account = $this->currentUser();
|
||||
$config = $this->config('user.settings');
|
||||
// When processing the one-time login link, we have to make sure that a user
|
||||
// isn't already logged in.
|
||||
if ($account->isAuthenticated()) {
|
||||
// The current user is already logged in.
|
||||
if ($account->id() == $uid) {
|
||||
user_logout();
|
||||
}
|
||||
// A different user is already logged in on the computer.
|
||||
else {
|
||||
if ($reset_link_user = $this->userStorage->load($uid)) {
|
||||
drupal_set_message($this->t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please <a href="@logout">logout</a> and try using the link again.',
|
||||
array('%other_user' => $account->getUsername(), '%resetting_user' => $reset_link_user->getUsername(), '@logout' => $this->url('user.logout'))), 'warning');
|
||||
}
|
||||
else {
|
||||
// Invalid one-time link specifies an unknown user.
|
||||
drupal_set_message($this->t('The one-time login link you clicked is invalid.'));
|
||||
}
|
||||
return $this->redirect('<front>');
|
||||
}
|
||||
}
|
||||
// The current user is not logged in, so check the parameters.
|
||||
// Time out, in seconds, until login URL expires.
|
||||
$timeout = $config->get('password_reset_timeout');
|
||||
$current = REQUEST_TIME;
|
||||
|
||||
/* @var \Drupal\user\UserInterface $user */
|
||||
$user = $this->userStorage->load($uid);
|
||||
|
||||
// Verify that the user exists and is active.
|
||||
if ($user && $user->isActive()) {
|
||||
// No time out for first time login.
|
||||
if ($user->getLastLoginTime() && $current - $timestamp > $timeout) {
|
||||
drupal_set_message($this->t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'error');
|
||||
return $this->redirect('user.pass');
|
||||
}
|
||||
elseif ($user->isAuthenticated() && ($timestamp >= $user->getLastLoginTime()) && ($timestamp <= $current) && ($hash === user_pass_rehash($user->getPassword(), $timestamp, $user->getLastLoginTime(), $user->id()))) {
|
||||
$expiration_date = $user->getLastLoginTime() ? $this->dateFormatter->format($timestamp + $timeout) : NULL;
|
||||
return $this->formBuilder()->getForm('Drupal\user\Form\UserPasswordResetForm', $user, $expiration_date, $timestamp, $hash);
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'), 'error');
|
||||
return $this->redirect('user.pass');
|
||||
}
|
||||
}
|
||||
// Blocked or invalid user ID, so deny access. The parameters will be in the
|
||||
// watchdog's URL for the administrator to check.
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects users to their profile page.
|
||||
*
|
||||
* This controller assumes that it is only invoked for authenticated users.
|
||||
* This is enforced for the 'user.page' route with the '_user_is_logged_in'
|
||||
* requirement.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* Returns a redirect to the profile of the currently logged in user.
|
||||
*/
|
||||
public function userPage() {
|
||||
return $this->redirect('entity.user.canonical', array('user' => $this->currentUser()->id()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Route title callback.
|
||||
*
|
||||
* @param \Drupal\user\UserInterface $user
|
||||
* The user account.
|
||||
*
|
||||
* @return string
|
||||
* The user account name.
|
||||
*/
|
||||
public function userTitle(UserInterface $user = NULL) {
|
||||
return $user ? Xss::filter($user->getUsername()) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the current user out.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* A redirection to home page.
|
||||
*/
|
||||
public function logout() {
|
||||
user_logout();
|
||||
return $this->redirect('<front>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms cancelling a user account via an email link.
|
||||
*
|
||||
* @param \Drupal\user\UserInterface $user
|
||||
* The user account.
|
||||
* @param int $timestamp
|
||||
* The timestamp.
|
||||
* @param string $hashed_pass
|
||||
* The hashed password.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
* A redirect response.
|
||||
*/
|
||||
public function confirmCancel(UserInterface $user, $timestamp = 0, $hashed_pass = '') {
|
||||
// Time out in seconds until cancel URL expires; 24 hours = 86400 seconds.
|
||||
$timeout = 86400;
|
||||
$current = REQUEST_TIME;
|
||||
|
||||
// Basic validation of arguments.
|
||||
$account_data = $this->userData->get('user', $user->id());
|
||||
if (isset($account_data['cancel_method']) && !empty($timestamp) && !empty($hashed_pass)) {
|
||||
// Validate expiration and hashed password/login.
|
||||
if ($timestamp <= $current && $current - $timestamp < $timeout && $user->id() && $timestamp >= $user->getLastLoginTime() && $hashed_pass == user_pass_rehash($user->getPassword(), $timestamp, $user->getLastLoginTime(), $user->id())) {
|
||||
$edit = array(
|
||||
'user_cancel_notify' => isset($account_data['cancel_notify']) ? $account_data['cancel_notify'] : $this->config('user.settings')->get('notify.status_canceled'),
|
||||
);
|
||||
user_cancel($edit, $user->id(), $account_data['cancel_method']);
|
||||
// Since user_cancel() is not invoked via Form API, batch processing
|
||||
// needs to be invoked manually and should redirect to the front page
|
||||
// after completion.
|
||||
return batch_process('');
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'));
|
||||
return $this->redirect('entity.user.cancel_form', ['user' => $user->id()], ['absolute' => TRUE]);
|
||||
}
|
||||
}
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
}
|
189
core/modules/user/src/Entity/Role.php
Normal file
189
core/modules/user/src/Entity/Role.php
Normal file
|
@ -0,0 +1,189 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Entity\Role.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Entity;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Defines the user role entity class.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "user_role",
|
||||
* label = @Translation("Role"),
|
||||
* handlers = {
|
||||
* "storage" = "Drupal\user\RoleStorage",
|
||||
* "access" = "Drupal\user\RoleAccessControlHandler",
|
||||
* "list_builder" = "Drupal\user\RoleListBuilder",
|
||||
* "form" = {
|
||||
* "default" = "Drupal\user\RoleForm",
|
||||
* "delete" = "Drupal\Core\Entity\EntityDeleteForm"
|
||||
* }
|
||||
* },
|
||||
* admin_permission = "administer permissions",
|
||||
* config_prefix = "role",
|
||||
* static_cache = TRUE,
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "weight" = "weight",
|
||||
* "label" = "label"
|
||||
* },
|
||||
* links = {
|
||||
* "delete-form" = "/admin/people/roles/manage/{user_role}/delete",
|
||||
* "edit-form" = "/admin/people/roles/manage/{user_role}",
|
||||
* "edit-permissions-form" = "/admin/people/permissions/{user_role}",
|
||||
* "collection" = "/admin/people/roles",
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "label",
|
||||
* "weight",
|
||||
* "is_admin",
|
||||
* "permissions",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class Role extends ConfigEntityBase implements RoleInterface {
|
||||
|
||||
/**
|
||||
* The machine name of this role.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The human-readable label of this role.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The weight of this role in administrative listings.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $weight;
|
||||
|
||||
/**
|
||||
* The permissions belonging to this role.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $permissions = array();
|
||||
|
||||
/**
|
||||
* An indicator whether the role has all permissions.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $is_admin;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPermissions() {
|
||||
if ($this->isAdmin()) {
|
||||
return [];
|
||||
}
|
||||
return $this->permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getWeight() {
|
||||
return $this->get('weight');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setWeight($weight) {
|
||||
$this->set('weight', $weight);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasPermission($permission) {
|
||||
if ($this->isAdmin()) {
|
||||
return TRUE;
|
||||
}
|
||||
return in_array($permission, $this->permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function grantPermission($permission) {
|
||||
if ($this->isAdmin()) {
|
||||
return $this;
|
||||
}
|
||||
if (!$this->hasPermission($permission)) {
|
||||
$this->permissions[] = $permission;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function revokePermission($permission) {
|
||||
if ($this->isAdmin()) {
|
||||
return $this;
|
||||
}
|
||||
$this->permissions = array_diff($this->permissions, array($permission));
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isAdmin() {
|
||||
return (bool) $this->is_admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setIsAdmin($is_admin) {
|
||||
$this->is_admin = $is_admin;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function postLoad(EntityStorageInterface $storage, array &$entities) {
|
||||
parent::postLoad($storage, $entities);
|
||||
// Sort the queried roles by their weight.
|
||||
// See \Drupal\Core\Config\Entity\ConfigEntityBase::sort().
|
||||
uasort($entities, 'static::sort');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
parent::preSave($storage);
|
||||
|
||||
if (!isset($this->weight) && ($roles = $storage->loadMultiple())) {
|
||||
// Set a role weight to make this new role last.
|
||||
$max = array_reduce($roles, function($max, $role) {
|
||||
return $max > $role->weight ? $max : $role->weight;
|
||||
});
|
||||
$this->weight = $max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
565
core/modules/user/src/Entity/User.php
Normal file
565
core/modules/user/src/Entity/User.php
Normal file
|
@ -0,0 +1,565 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Entity\User.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Entity;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityBase;
|
||||
use Drupal\Core\Entity\EntityChangedTrait;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\user\RoleInterface;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Defines the user entity class.
|
||||
*
|
||||
* The base table name here is plural, despite Drupal table naming standards,
|
||||
* because "user" is a reserved word in many databases.
|
||||
*
|
||||
* @ContentEntityType(
|
||||
* id = "user",
|
||||
* label = @Translation("User"),
|
||||
* handlers = {
|
||||
* "storage" = "Drupal\user\UserStorage",
|
||||
* "storage_schema" = "Drupal\user\UserStorageSchema",
|
||||
* "access" = "Drupal\user\UserAccessControlHandler",
|
||||
* "list_builder" = "Drupal\user\UserListBuilder",
|
||||
* "views_data" = "Drupal\user\UserViewsData",
|
||||
* "route_provider" = {
|
||||
* "html" = "Drupal\user\Entity\UserRouteProvider",
|
||||
* },
|
||||
* "form" = {
|
||||
* "default" = "Drupal\user\ProfileForm",
|
||||
* "cancel" = "Drupal\user\Form\UserCancelForm",
|
||||
* "register" = "Drupal\user\RegisterForm"
|
||||
* },
|
||||
* "translation" = "Drupal\user\ProfileTranslationHandler"
|
||||
* },
|
||||
* admin_permission = "administer users",
|
||||
* base_table = "users",
|
||||
* data_table = "users_field_data",
|
||||
* label_callback = "user_format_name",
|
||||
* translatable = TRUE,
|
||||
* entity_keys = {
|
||||
* "id" = "uid",
|
||||
* "langcode" = "langcode",
|
||||
* "uuid" = "uuid"
|
||||
* },
|
||||
* links = {
|
||||
* "canonical" = "/user/{user}",
|
||||
* "edit-form" = "/user/{user}/edit",
|
||||
* "cancel-form" = "/user/{user}/cancel",
|
||||
* "collection" = "/admin/people",
|
||||
* },
|
||||
* field_ui_base_route = "entity.user.admin_form",
|
||||
* common_reference_target = TRUE
|
||||
* )
|
||||
*/
|
||||
class User extends ContentEntityBase implements UserInterface {
|
||||
|
||||
use EntityChangedTrait;
|
||||
|
||||
/**
|
||||
* Stores a reference for a reusable anonymous user entity.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected static $anonymousUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isNew() {
|
||||
return !empty($this->enforceIsNew) || $this->id() === NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
parent::preSave($storage);
|
||||
|
||||
// Make sure that the authenticated/anonymous roles are not persisted.
|
||||
foreach ($this->get('roles') as $index => $item) {
|
||||
if (in_array($item->target_id, array(RoleInterface::ANONYMOUS_ID, RoleInterface::AUTHENTICATED_ID))) {
|
||||
$this->get('roles')->offsetUnset($index);
|
||||
}
|
||||
}
|
||||
|
||||
// Store account cancellation information.
|
||||
foreach (array('user_cancel_method', 'user_cancel_notify') as $key) {
|
||||
if (isset($this->{$key})) {
|
||||
\Drupal::service('user.data')->set('user', $this->id(), substr($key, 5), $this->{$key});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
|
||||
parent::postSave($storage, $update);
|
||||
|
||||
if ($update) {
|
||||
$session_manager = \Drupal::service('session_manager');
|
||||
// If the password has been changed, delete all open sessions for the
|
||||
// user and recreate the current one.
|
||||
if ($this->pass->value != $this->original->pass->value) {
|
||||
$session_manager->delete($this->id());
|
||||
if ($this->id() == \Drupal::currentUser()->id()) {
|
||||
\Drupal::service('session')->migrate();
|
||||
}
|
||||
}
|
||||
|
||||
// If the user was blocked, delete the user's sessions to force a logout.
|
||||
if ($this->original->status->value != $this->status->value && $this->status->value == 0) {
|
||||
$session_manager->delete($this->id());
|
||||
}
|
||||
|
||||
// Send emails after we have the new user object.
|
||||
if ($this->status->value != $this->original->status->value) {
|
||||
// The user's status is changing; conditionally send notification email.
|
||||
$op = $this->status->value == 1 ? 'status_activated' : 'status_blocked';
|
||||
_user_mail_notify($op, $this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function postDelete(EntityStorageInterface $storage, array $entities) {
|
||||
parent::postDelete($storage, $entities);
|
||||
|
||||
$uids = array_keys($entities);
|
||||
\Drupal::service('user.data')->delete(NULL, $uids);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRoles($exclude_locked_roles = FALSE) {
|
||||
$roles = array();
|
||||
|
||||
// Users with an ID always have the authenticated user role.
|
||||
if (!$exclude_locked_roles) {
|
||||
if ($this->isAuthenticated()) {
|
||||
$roles[] = RoleInterface::AUTHENTICATED_ID;
|
||||
}
|
||||
else {
|
||||
$roles[] = RoleInterface::ANONYMOUS_ID;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->get('roles') as $role) {
|
||||
if ($role->target_id) {
|
||||
$roles[] = $role->target_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasRole($rid) {
|
||||
return in_array($rid, $this->getRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addRole($rid) {
|
||||
|
||||
if (in_array($rid, [RoleInterface::AUTHENTICATED_ID, RoleInterface::ANONYMOUS_ID])) {
|
||||
throw new \InvalidArgumentException('Anonymous or authenticated role ID must not be assigned manually.');
|
||||
}
|
||||
|
||||
$roles = $this->getRoles(TRUE);
|
||||
$roles[] = $rid;
|
||||
$this->set('roles', array_unique($roles));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeRole($rid) {
|
||||
$this->set('roles', array_diff($this->getRoles(TRUE), array($rid)));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasPermission($permission) {
|
||||
// User #1 has all privileges.
|
||||
if ((int) $this->id() === 1) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return $this->getRoleStorage()->isPermissionInRoles($permission, $this->getRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPassword() {
|
||||
return $this->get('pass')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setPassword($password) {
|
||||
$this->get('pass')->value = $password;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getEmail() {
|
||||
return $this->get('mail')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setEmail($mail) {
|
||||
$this->get('mail')->value = $mail;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCreatedTime() {
|
||||
return $this->get('created')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLastAccessedTime() {
|
||||
return $this->get('access')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setLastAccessTime($timestamp) {
|
||||
$this->get('access')->value = $timestamp;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLastLoginTime() {
|
||||
return $this->get('login')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setLastLoginTime($timestamp) {
|
||||
$this->get('login')->value = $timestamp;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isActive() {
|
||||
return $this->get('status')->value == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isBlocked() {
|
||||
return $this->get('status')->value == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function activate() {
|
||||
$this->get('status')->value = 1;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function block() {
|
||||
$this->get('status')->value = 0;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTimeZone() {
|
||||
return $this->get('timezone')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function getPreferredLangcode($fallback_to_default = TRUE) {
|
||||
$language_list = $this->languageManager()->getLanguages();
|
||||
$preferred_langcode = $this->get('preferred_langcode')->value;
|
||||
if (!empty($preferred_langcode) && isset($language_list[$preferred_langcode])) {
|
||||
return $language_list[$preferred_langcode]->getId();
|
||||
}
|
||||
else {
|
||||
return $fallback_to_default ? $this->languageManager()->getDefaultLanguage()->getId() : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function getPreferredAdminLangcode($fallback_to_default = TRUE) {
|
||||
$language_list = $this->languageManager()->getLanguages();
|
||||
$preferred_langcode = $this->get('preferred_admin_langcode')->value;
|
||||
if (!empty($preferred_langcode) && isset($language_list[$preferred_langcode])) {
|
||||
return $language_list[$preferred_langcode]->getId();
|
||||
}
|
||||
else {
|
||||
return $fallback_to_default ? $this->languageManager()->getDefaultLanguage()->getId() : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInitialEmail() {
|
||||
return $this->get('init')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isAuthenticated() {
|
||||
return $this->id() > 0;
|
||||
}
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isAnonymous() {
|
||||
return $this->id() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUsername() {
|
||||
$name = $this->get('name')->value ?: \Drupal::config('user.settings')->get('anonymous');
|
||||
\Drupal::moduleHandler()->alter('user_format_name', $name, $this);
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUsername($username) {
|
||||
$this->set('name', $username);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getChangedTime() {
|
||||
return $this->get('changed')->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setExistingPassword($password) {
|
||||
$this->get('pass')->existing = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function checkExistingPassword(UserInterface $account_unchanged) {
|
||||
return !empty($this->get('pass')->existing) && \Drupal::service('password')->check(trim($this->get('pass')->existing), $account_unchanged->getPassword());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an anonymous user entity.
|
||||
*
|
||||
* @return \Drupal\user\UserInterface
|
||||
* An anonymous user entity.
|
||||
*/
|
||||
public static function getAnonymousUser() {
|
||||
if (!isset(static::$anonymousUser)) {
|
||||
|
||||
// @todo Use the entity factory once available, see
|
||||
// https://www.drupal.org/node/1867228.
|
||||
$entity_manager = \Drupal::entityManager();
|
||||
$entity_type = $entity_manager->getDefinition('user');
|
||||
$class = $entity_type->getClass();
|
||||
|
||||
static::$anonymousUser = new $class(['uid' => [LanguageInterface::LANGCODE_DEFAULT => 0]], $entity_type->id());
|
||||
}
|
||||
return clone static::$anonymousUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
|
||||
$fields['uid'] = BaseFieldDefinition::create('integer')
|
||||
->setLabel(t('User ID'))
|
||||
->setDescription(t('The user ID.'))
|
||||
->setReadOnly(TRUE)
|
||||
->setSetting('unsigned', TRUE);
|
||||
|
||||
$fields['uuid'] = BaseFieldDefinition::create('uuid')
|
||||
->setLabel(t('UUID'))
|
||||
->setDescription(t('The user UUID.'))
|
||||
->setReadOnly(TRUE);
|
||||
|
||||
$fields['langcode'] = BaseFieldDefinition::create('language')
|
||||
->setLabel(t('Language code'))
|
||||
->setDescription(t('The user language code.'))
|
||||
->setTranslatable(TRUE);
|
||||
|
||||
$fields['preferred_langcode'] = BaseFieldDefinition::create('language')
|
||||
->setLabel(t('Preferred language code'))
|
||||
->setDescription(t("The user's preferred language code for receiving emails and viewing the site."))
|
||||
// @todo: Define this via an options provider once
|
||||
// https://www.drupal.org/node/2329937 is completed.
|
||||
->addPropertyConstraints('value', array(
|
||||
'AllowedValues' => array('callback' => __CLASS__ . '::getAllowedConfigurableLanguageCodes'),
|
||||
));
|
||||
|
||||
$fields['preferred_admin_langcode'] = BaseFieldDefinition::create('language')
|
||||
->setLabel(t('Preferred admin language code'))
|
||||
->setDescription(t("The user's preferred language code for viewing administration pages."))
|
||||
// @todo: A default value of NULL is ignored, so we have to specify
|
||||
// an empty field item structure instead. Fix this in
|
||||
// https://www.drupal.org/node/2318605.
|
||||
->setDefaultValue(array(0 => array ('value' => NULL)))
|
||||
// @todo: Define this via an options provider once
|
||||
// https://www.drupal.org/node/2329937 is completed.
|
||||
->addPropertyConstraints('value', array(
|
||||
'AllowedValues' => array('callback' => __CLASS__ . '::getAllowedConfigurableLanguageCodes'),
|
||||
));
|
||||
|
||||
// The name should not vary per language. The username is the visual
|
||||
// identifier for a user and needs to be consistent in all languages.
|
||||
$fields['name'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Name'))
|
||||
->setDescription(t('The name of this user.'))
|
||||
->setDefaultValue('')
|
||||
->setConstraints(array(
|
||||
// No Length constraint here because the UserName constraint also covers
|
||||
// that.
|
||||
'UserName' => array(),
|
||||
'UserNameUnique' => array(),
|
||||
));
|
||||
|
||||
$fields['pass'] = BaseFieldDefinition::create('password')
|
||||
->setLabel(t('Password'))
|
||||
->setDescription(t('The password of this user (hashed).'))
|
||||
->addConstraint('ProtectedUserField');
|
||||
|
||||
$fields['mail'] = BaseFieldDefinition::create('email')
|
||||
->setLabel(t('Email'))
|
||||
->setDescription(t('The email of this user.'))
|
||||
->setDefaultValue('')
|
||||
->addConstraint('UserMailUnique')
|
||||
->addConstraint('UserMailRequired')
|
||||
->addConstraint('ProtectedUserField');
|
||||
|
||||
$fields['timezone'] = BaseFieldDefinition::create('string')
|
||||
->setLabel(t('Timezone'))
|
||||
->setDescription(t('The timezone of this user.'))
|
||||
->setSetting('max_length', 32)
|
||||
// @todo: Define this via an options provider once
|
||||
// https://www.drupal.org/node/2329937 is completed.
|
||||
->addPropertyConstraints('value', array(
|
||||
'AllowedValues' => array('callback' => __CLASS__ . '::getAllowedTimezones'),
|
||||
));
|
||||
|
||||
$fields['status'] = BaseFieldDefinition::create('boolean')
|
||||
->setLabel(t('User status'))
|
||||
->setDescription(t('Whether the user is active or blocked.'))
|
||||
->setDefaultValue(FALSE);
|
||||
|
||||
$fields['created'] = BaseFieldDefinition::create('created')
|
||||
->setLabel(t('Created'))
|
||||
->setDescription(t('The time that the user was created.'));
|
||||
|
||||
$fields['changed'] = BaseFieldDefinition::create('changed')
|
||||
->setLabel(t('Changed'))
|
||||
->setDescription(t('The time that the user was last edited.'))
|
||||
->setTranslatable(TRUE);
|
||||
|
||||
$fields['access'] = BaseFieldDefinition::create('timestamp')
|
||||
->setLabel(t('Last access'))
|
||||
->setDescription(t('The time that the user last accessed the site.'))
|
||||
->setDefaultValue(0);
|
||||
|
||||
$fields['login'] = BaseFieldDefinition::create('timestamp')
|
||||
->setLabel(t('Last login'))
|
||||
->setDescription(t('The time that the user last logged in.'))
|
||||
->setDefaultValue(0);
|
||||
|
||||
$fields['init'] = BaseFieldDefinition::create('email')
|
||||
->setLabel(t('Initial email'))
|
||||
->setDescription(t('The email address used for initial account creation.'))
|
||||
->setDefaultValue('');
|
||||
|
||||
$fields['roles'] = BaseFieldDefinition::create('entity_reference')
|
||||
->setLabel(t('Roles'))
|
||||
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
|
||||
->setDescription(t('The roles the user has.'))
|
||||
->setSetting('target_type', 'user_role');
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the role storage object.
|
||||
*
|
||||
* @return \Drupal\user\RoleStorageInterface
|
||||
* The role storage object.
|
||||
*/
|
||||
protected function getRoleStorage() {
|
||||
return \Drupal::entityManager()->getStorage('user_role');
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines allowed timezones for the field's AllowedValues constraint.
|
||||
*
|
||||
* @return string[]
|
||||
* The allowed values.
|
||||
*/
|
||||
public static function getAllowedTimezones() {
|
||||
return array_keys(system_time_zones());
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines allowed configurable language codes for AllowedValues constraints.
|
||||
*
|
||||
* @return string[]
|
||||
* The allowed values.
|
||||
*/
|
||||
public static function getAllowedConfigurableLanguageCodes() {
|
||||
return array_keys(\Drupal::languageManager()->getLanguages(LanguageInterface::STATE_CONFIGURABLE));
|
||||
}
|
||||
|
||||
}
|
54
core/modules/user/src/Entity/UserRouteProvider.php
Normal file
54
core/modules/user/src/Entity/UserRouteProvider.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Entity\UserRouteProvider.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Entity;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\Routing\EntityRouteProviderInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* Provides routes for the user entity.
|
||||
*/
|
||||
class UserRouteProvider implements EntityRouteProviderInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRoutes(EntityTypeInterface $entity_type) {
|
||||
$route_collection = new RouteCollection();
|
||||
$route = (new Route('/user/{user}'))
|
||||
->setDefaults([
|
||||
'_entity_view' => 'user.full',
|
||||
'_title_callback' => 'Drupal\user\Controller\UserController::userTitle',
|
||||
])
|
||||
->setRequirement('_entity_access', 'user.view');
|
||||
$route_collection->add('entity.user.canonical', $route);
|
||||
|
||||
$route = (new Route('/user/{user}/edit'))
|
||||
->setDefaults([
|
||||
'_entity_form' => 'user.default',
|
||||
'_title_callback' => 'Drupal\user\Controller\UserController::userTitle',
|
||||
])
|
||||
->setOption('_admin_route', TRUE)
|
||||
->setRequirement('_entity_access', 'user.update');
|
||||
$route_collection->add('entity.user.edit_form', $route);
|
||||
|
||||
$route = (new Route('/user/{user}/cancel'))
|
||||
->setDefaults([
|
||||
'_title' => 'Cancel account',
|
||||
'_entity_form' => 'user.cancel',
|
||||
])
|
||||
->setOption('_admin_route', TRUE)
|
||||
->setRequirement('_entity_access', 'user.delete');
|
||||
$route_collection->add('entity.user.cancel_form', $route);
|
||||
|
||||
return $route_collection;
|
||||
}
|
||||
|
||||
}
|
56
core/modules/user/src/EntityOwnerInterface.php
Normal file
56
core/modules/user/src/EntityOwnerInterface.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\EntityOwnerInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
/**
|
||||
* Defines a common interface for entities that have an owner.
|
||||
*
|
||||
* An owner is someone who has primary control over an entity, similar to
|
||||
* owners in Unix file system access. This may or may not be the entity's
|
||||
* original author. The owner may also have less permissions than other users,
|
||||
* such as administrators.
|
||||
*/
|
||||
interface EntityOwnerInterface {
|
||||
|
||||
/**
|
||||
* Returns the entity owner's user entity.
|
||||
*
|
||||
* @return \Drupal\user\UserInterface
|
||||
* The owner user entity.
|
||||
*/
|
||||
public function getOwner();
|
||||
|
||||
/**
|
||||
* Sets the entity owner's user entity.
|
||||
*
|
||||
* @param \Drupal\user\UserInterface $account
|
||||
* The owner user entity.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOwner(UserInterface $account);
|
||||
|
||||
/**
|
||||
* Returns the entity owner's user ID.
|
||||
*
|
||||
* @return int
|
||||
* The owner user ID.
|
||||
*/
|
||||
public function getOwnerId();
|
||||
|
||||
/**
|
||||
* Sets the entity owner's user ID.
|
||||
*
|
||||
* @param int $uid
|
||||
* The owner user id.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOwnerId($uid);
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\EventSubscriber\AccessDeniedSubscriber.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
use Drupal\Core\Routing\UrlGeneratorTrait;
|
||||
use Drupal\Core\Routing\UrlGeneratorInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Redirects users when access is denied.
|
||||
*
|
||||
* Anonymous users are taken to the login page when attempting to access the
|
||||
* user profile pages. Authenticated users are redirected from the login form to
|
||||
* their profile page and from the user registration form to their profile edit
|
||||
* form.
|
||||
*/
|
||||
class AccessDeniedSubscriber implements EventSubscriberInterface {
|
||||
|
||||
use UrlGeneratorTrait;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* Constructs a new redirect subscriber.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The current user.
|
||||
* @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
|
||||
* The URL generator.
|
||||
*/
|
||||
public function __construct(AccountInterface $account, URLGeneratorInterface $url_generator) {
|
||||
$this->account = $account;
|
||||
$this->setUrlGenerator($url_generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects users when access is denied.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function onException(GetResponseForExceptionEvent $event) {
|
||||
$exception = $event->getException();
|
||||
if ($exception instanceof AccessDeniedHttpException) {
|
||||
$route_name = RouteMatch::createFromRequest($event->getRequest())->getRouteName();
|
||||
if ($this->account->isAuthenticated()) {
|
||||
switch ($route_name) {
|
||||
case 'user.login';
|
||||
// Redirect an authenticated user to the profile page.
|
||||
$event->setResponse($this->redirect('entity.user.canonical', ['user' => $this->account->id()]));
|
||||
break;
|
||||
|
||||
case 'user.register';
|
||||
// Redirect an authenticated user to the profile form.
|
||||
$event->setResponse($this->redirect('entity.user.edit_form', ['user' => $this->account->id()]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
elseif ($route_name === 'user.page') {
|
||||
$event->setResponse($this->redirect('user.login'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
// Use a higher priority than
|
||||
// \Drupal\Core\EventSubscriber\ExceptionLoggingSubscriber, because there's
|
||||
// no need to log the exception if we can redirect.
|
||||
$events[KernelEvents::EXCEPTION][] = ['onException', 75];
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\EventSubscriber\MaintenanceModeSubscriber.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
use Drupal\Core\Routing\UrlGeneratorTrait;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Site\MaintenanceModeInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Maintenance mode subscriber to logout users.
|
||||
*/
|
||||
class MaintenanceModeSubscriber implements EventSubscriberInterface {
|
||||
|
||||
use UrlGeneratorTrait;
|
||||
|
||||
/**
|
||||
* The maintenance mode.
|
||||
*
|
||||
* @var \Drupal\Core\Site\MaintenanceMode
|
||||
*/
|
||||
protected $maintenanceMode;
|
||||
|
||||
/**
|
||||
* The current account.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* Constructs a new MaintenanceModeSubscriber.
|
||||
*
|
||||
* @param \Drupal\Core\Site\MaintenanceModeInterface $maintenance_mode
|
||||
* The maintenance mode.
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(MaintenanceModeInterface $maintenance_mode, AccountInterface $account) {
|
||||
$this->maintenanceMode = $maintenance_mode;
|
||||
$this->account = $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout users if site is in maintenance mode.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function onKernelRequestMaintenance(GetResponseEvent $event) {
|
||||
$request = $event->getRequest();
|
||||
$route_match = RouteMatch::createFromRequest($request);
|
||||
if ($this->maintenanceMode->applies($route_match)) {
|
||||
// If the site is offline, log out unprivileged users.
|
||||
if ($this->account->isAuthenticated() && !$this->maintenanceMode->exempt($this->account)) {
|
||||
user_logout();
|
||||
// Redirect to homepage.
|
||||
$event->setResponse($this->redirect($this->url('<front>')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events[KernelEvents::REQUEST][] = ['onKernelRequestMaintenance', 31];
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\EventSubscriber\UserRequestSubscriber.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\PostResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Updates the current user's last access time.
|
||||
*/
|
||||
class UserRequestSubscriber implements EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* The current account.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a new UserRequestSubscriber.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $account
|
||||
* The current user.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(AccountInterface $account, EntityManagerInterface $entity_manager) {
|
||||
$this->account = $account;
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current user's last access time.
|
||||
*
|
||||
* @param \Symfony\Component\HttpKernel\Event\PostResponseEvent $event
|
||||
* The event to process.
|
||||
*/
|
||||
public function onKernelTerminate(PostResponseEvent $event) {
|
||||
if ($this->account->isAuthenticated() && REQUEST_TIME - $this->account->getLastAccessedTime() > Settings::get('session_write_interval', 180)) {
|
||||
// Do that no more than once per 180 seconds.
|
||||
/** @var \Drupal\user\UserStorageInterface $storage */
|
||||
$storage = $this->entityManager->getStorage('user');
|
||||
$storage->updateLastAccessTimestamp($this->account, REQUEST_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
// Should go before other subscribers start to write their caches. Notably
|
||||
// before \Drupal\Core\EventSubscriber\KernelDestructionSubscriber to
|
||||
// prevent instantiation of destructed services.
|
||||
$events[KernelEvents::TERMINATE][] = ['onKernelTerminate', 300];
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
155
core/modules/user/src/Form/UserCancelForm.php
Normal file
155
core/modules/user/src/Form/UserCancelForm.php
Normal file
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Form\UserCancelForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Form;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Provides a confirmation form for cancelling user account.
|
||||
*/
|
||||
class UserCancelForm extends ContentEntityConfirmFormBase {
|
||||
|
||||
/**
|
||||
* Available account cancellation methods.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $cancelMethods;
|
||||
|
||||
/**
|
||||
* The user being cancelled.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
if ($this->entity->id() == $this->currentUser()->id()) {
|
||||
return $this->t('Are you sure you want to cancel your account?');
|
||||
}
|
||||
return $this->t('Are you sure you want to cancel the account %name?', array('%name' => $this->entity->label()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return $this->entity->urlInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
$description = '';
|
||||
$default_method = $this->config('user.settings')->get('cancel_method');
|
||||
if ($this->currentUser()->hasPermission('administer users') || $this->currentUser()->hasPermission('select account cancellation method')) {
|
||||
$description = $this->t('Select the method to cancel the account above.');
|
||||
}
|
||||
// Options supplied via user_cancel_methods() can have a custom
|
||||
// #confirm_description property for the confirmation form description.
|
||||
elseif (isset($this->cancelMethods[$default_method]['#confirm_description'])) {
|
||||
$description = $this->cancelMethods[$default_method]['#confirm_description'];
|
||||
}
|
||||
return $description . ' ' . $this->t('This action cannot be undone.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Cancel account');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$user = $this->currentUser();
|
||||
$this->cancelMethods = user_cancel_methods();
|
||||
|
||||
// Display account cancellation method selection, if allowed.
|
||||
$admin_access = $user->hasPermission('administer users');
|
||||
$form['user_cancel_method'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => ($this->entity->id() == $user->id() ? $this->t('When cancelling your account') : $this->t('When cancelling the account')),
|
||||
'#access' => $admin_access || $user->hasPermission('select account cancellation method'),
|
||||
);
|
||||
$form['user_cancel_method'] += $this->cancelMethods;
|
||||
|
||||
// Allow user administrators to skip the account cancellation confirmation
|
||||
// mail (by default), as long as they do not attempt to cancel their own
|
||||
// account.
|
||||
$override_access = $admin_access && ($this->entity->id() != $user->id());
|
||||
$form['user_cancel_confirm'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Require email confirmation to cancel account'),
|
||||
'#default_value' => !$override_access,
|
||||
'#access' => $override_access,
|
||||
'#description' => $this->t('When enabled, the user must confirm the account cancellation via email.'),
|
||||
);
|
||||
// Also allow to send account canceled notification mail, if enabled.
|
||||
$default_notify = $this->config('user.settings')->get('notify.status_canceled');
|
||||
$form['user_cancel_notify'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Notify user when account is canceled'),
|
||||
'#default_value' => ($override_access ? FALSE : $default_notify),
|
||||
'#access' => $override_access && $default_notify,
|
||||
'#description' => $this->t('When enabled, the user will receive an email notification after the account has been canceled.'),
|
||||
);
|
||||
|
||||
// Always provide entity id in the same form key as in the entity edit form.
|
||||
$form['uid'] = array('#type' => 'value', '#value' => $this->entity->id());
|
||||
|
||||
// Store the user permissions so that it can be altered in hook_form_alter()
|
||||
// if desired.
|
||||
$form['access'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $user->hasPermission('administer users'),
|
||||
);
|
||||
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
// Cancel account immediately, if the current user has administrative
|
||||
// privileges, no confirmation mail shall be sent, and the user does not
|
||||
// attempt to cancel the own account.
|
||||
if (!$form_state->isValueEmpty('access') && $form_state->isValueEmpty('user_cancel_confirm') && $this->entity->id() != $this->currentUser()->id()) {
|
||||
user_cancel($form_state->getValues(), $this->entity->id(), $form_state->getValue('user_cancel_method'));
|
||||
|
||||
$form_state->setRedirectUrl($this->entity->urlInfo('collection'));
|
||||
}
|
||||
else {
|
||||
// Store cancelling method and whether to notify the user in
|
||||
// $this->entity for
|
||||
// \Drupal\user\Controller\UserController::confirmCancel().
|
||||
$this->entity->user_cancel_method = $form_state->getValue('user_cancel_method');
|
||||
$this->entity->user_cancel_notify = $form_state->getValue('user_cancel_notify');
|
||||
$this->entity->save();
|
||||
_user_mail_notify('cancel_confirm', $this->entity);
|
||||
drupal_set_message($this->t('A confirmation request to cancel your account has been sent to your email address.'));
|
||||
$this->logger('user')->notice('Sent account cancellation request to %name %email.', array('%name' => $this->entity->label(), '%email' => '<' . $this->entity->getEmail() . '>'));
|
||||
|
||||
$form_state->setRedirect(
|
||||
'entity.user.canonical',
|
||||
array('user' => $this->entity->id())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
254
core/modules/user/src/Form/UserLoginForm.php
Normal file
254
core/modules/user/src/Form/UserLoginForm.php
Normal file
|
@ -0,0 +1,254 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Form\UserLoginForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Form;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Flood\FloodInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\user\UserAuthInterface;
|
||||
use Drupal\user\UserStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a user login form.
|
||||
*/
|
||||
class UserLoginForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The flood service.
|
||||
*
|
||||
* @var \Drupal\Core\Flood\FloodInterface
|
||||
*/
|
||||
protected $flood;
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\user\UserStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* The user authentication object.
|
||||
*
|
||||
* @var \Drupal\user\UserAuthInterface
|
||||
*/
|
||||
protected $userAuth;
|
||||
|
||||
/**
|
||||
* The renderer.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RendererInterface
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* Constructs a new UserLoginForm.
|
||||
*
|
||||
* @param \Drupal\Core\Flood\FloodInterface $flood
|
||||
* The flood service.
|
||||
* @param \Drupal\user\UserStorageInterface $user_storage
|
||||
* The user storage.
|
||||
* @param \Drupal\user\UserAuthInterface $user_auth
|
||||
* The user authentication object.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer.
|
||||
*/
|
||||
public function __construct(FloodInterface $flood, UserStorageInterface $user_storage, UserAuthInterface $user_auth, RendererInterface $renderer) {
|
||||
$this->flood = $flood;
|
||||
$this->userStorage = $user_storage;
|
||||
$this->userAuth = $user_auth;
|
||||
$this->renderer = $renderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('flood'),
|
||||
$container->get('entity.manager')->getStorage('user'),
|
||||
$container->get('user.auth'),
|
||||
$container->get('renderer')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'user_login_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$config = $this->config('system.site');
|
||||
|
||||
// Display login form:
|
||||
$form['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Username'),
|
||||
'#size' => 60,
|
||||
'#maxlength' => USERNAME_MAX_LENGTH,
|
||||
'#description' => $this->t('Enter your @s username.', array('@s' => $config->get('name'))),
|
||||
'#required' => TRUE,
|
||||
'#attributes' => array(
|
||||
'autocorrect' => 'none',
|
||||
'autocapitalize' => 'none',
|
||||
'spellcheck' => 'false',
|
||||
'autofocus' => 'autofocus',
|
||||
),
|
||||
);
|
||||
|
||||
$form['pass'] = array(
|
||||
'#type' => 'password',
|
||||
'#title' => $this->t('Password'),
|
||||
'#size' => 60,
|
||||
'#description' => $this->t('Enter the password that accompanies your username.'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Log in'));
|
||||
|
||||
$form['#validate'][] = '::validateName';
|
||||
$form['#validate'][] = '::validateAuthentication';
|
||||
$form['#validate'][] = '::validateFinal';
|
||||
|
||||
$this->renderer->addCacheableDependency($form, $config);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$account = $this->userStorage->load($form_state->get('uid'));
|
||||
|
||||
// A destination was set, probably on an exception controller,
|
||||
if (!$this->getRequest()->request->has('destination')) {
|
||||
$form_state->setRedirect(
|
||||
'entity.user.canonical',
|
||||
array('user' => $account->id())
|
||||
);
|
||||
}
|
||||
else {
|
||||
$this->getRequest()->query->set('destination', $this->getRequest()->request->get('destination'));
|
||||
}
|
||||
|
||||
user_login_finalize($account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an error if supplied username has been blocked.
|
||||
*/
|
||||
public function validateName(array &$form, FormStateInterface $form_state) {
|
||||
if (!$form_state->isValueEmpty('name') && user_is_blocked($form_state->getValue('name'))) {
|
||||
// Blocked in user administration.
|
||||
$form_state->setErrorByName('name', $this->t('The username %name has not been activated or is blocked.', array('%name' => $form_state->getValue('name'))));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks supplied username/password against local users table.
|
||||
*
|
||||
* If successful, $form_state->get('uid') is set to the matching user ID.
|
||||
*/
|
||||
public function validateAuthentication(array &$form, FormStateInterface $form_state) {
|
||||
$password = trim($form_state->getValue('pass'));
|
||||
$flood_config = $this->config('user.flood');
|
||||
if (!$form_state->isValueEmpty('name') && !empty($password)) {
|
||||
// Do not allow any login from the current user's IP if the limit has been
|
||||
// reached. Default is 50 failed attempts allowed in one hour. This is
|
||||
// independent of the per-user limit to catch attempts from one IP to log
|
||||
// in to many different user accounts. We have a reasonably high limit
|
||||
// since there may be only one apparent IP for all users at an institution.
|
||||
if (!$this->flood->isAllowed('user.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) {
|
||||
$form_state->set('flood_control_triggered', 'ip');
|
||||
return;
|
||||
}
|
||||
$accounts = $this->userStorage->loadByProperties(array('name' => $form_state->getValue('name'), 'status' => 1));
|
||||
$account = reset($accounts);
|
||||
if ($account) {
|
||||
if ($flood_config->get('uid_only')) {
|
||||
// Register flood events based on the uid only, so they apply for any
|
||||
// IP address. This is the most secure option.
|
||||
$identifier = $account->id();
|
||||
}
|
||||
else {
|
||||
// The default identifier is a combination of uid and IP address. This
|
||||
// is less secure but more resistant to denial-of-service attacks that
|
||||
// could lock out all users with public user names.
|
||||
$identifier = $account->id() . '-' . $this->getRequest()->getClientIP();
|
||||
}
|
||||
$form_state->set('flood_control_user_identifier', $identifier);
|
||||
|
||||
// Don't allow login if the limit for this user has been reached.
|
||||
// Default is to allow 5 failed attempts every 6 hours.
|
||||
if (!$this->flood->isAllowed('user.failed_login_user', $flood_config->get('user_limit'), $flood_config->get('user_window'), $identifier)) {
|
||||
$form_state->set('flood_control_triggered', 'user');
|
||||
return;
|
||||
}
|
||||
}
|
||||
// We are not limited by flood control, so try to authenticate.
|
||||
// Store $uid in form state as a flag for self::validateFinal().
|
||||
$uid = $this->userAuth->authenticate($form_state->getValue('name'), $password);
|
||||
$form_state->set('uid', $uid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if user was not authenticated, or if too many logins were attempted.
|
||||
*
|
||||
* This validation function should always be the last one.
|
||||
*/
|
||||
public function validateFinal(array &$form, FormStateInterface $form_state) {
|
||||
$flood_config = $this->config('user.flood');
|
||||
if (!$form_state->get('uid')) {
|
||||
// Always register an IP-based failed login event.
|
||||
$this->flood->register('user.failed_login_ip', $flood_config->get('ip_window'));
|
||||
// Register a per-user failed login event.
|
||||
if ($flood_control_user_identifier = $form_state->get('flood_control_user_identifier')) {
|
||||
$this->flood->register('user.failed_login_user', $flood_config->get('user_window'), $flood_control_user_identifier);
|
||||
}
|
||||
|
||||
if ($flood_control_triggered = $form_state->get('flood_control_triggered')) {
|
||||
if ($flood_control_triggered == 'user') {
|
||||
$form_state->setErrorByName('name', $this->formatPlural($flood_config->get('user_limit'), 'Sorry, 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>.', 'Sorry, 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>.', array('@url' => $this->url('user.pass'))));
|
||||
}
|
||||
else {
|
||||
// We did not find a uid, so the limit is IP-based.
|
||||
$form_state->setErrorByName('name', $this->t('Sorry, 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>.', array('@url' => $this->url('user.pass'))));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$form_state->setErrorByName('name', $this->t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => $this->url('user.pass', [], array('query' => array('name' => $form_state->getValue('name')))))));
|
||||
$accounts = $this->userStorage->loadByProperties(array('name' => $form_state->getValue('name')));
|
||||
if (!empty($accounts)) {
|
||||
$this->logger('user')->notice('Login attempt failed for %user.', array('%user' => $form_state->getValue('name')));
|
||||
}
|
||||
else {
|
||||
// If the username entered is not a valid user,
|
||||
// only store the IP address.
|
||||
$this->logger('user')->notice('Login attempt failed from %ip.', array('%ip' => $this->getRequest()->getClientIp()));
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($flood_control_user_identifier = $form_state->get('flood_control_user_identifier')) {
|
||||
// Clear past failures for this user so as not to block a user who might
|
||||
// log in and out more than once in an hour.
|
||||
$this->flood->clear('user.failed_login_user', $flood_control_user_identifier);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
205
core/modules/user/src/Form/UserMultipleCancelConfirm.php
Normal file
205
core/modules/user/src/Form/UserMultipleCancelConfirm.php
Normal file
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Form\UserMultipleCancelConfirm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\user\PrivateTempStoreFactory;
|
||||
use Drupal\user\UserStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a confirmation form for cancelling multiple user accounts.
|
||||
*/
|
||||
class UserMultipleCancelConfirm extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* The temp store factory.
|
||||
*
|
||||
* @var \Drupal\user\PrivateTempStoreFactory
|
||||
*/
|
||||
protected $tempStoreFactory;
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\user\UserStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* Constructs a new UserMultipleCancelConfirm.
|
||||
*
|
||||
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
|
||||
* The temp store factory.
|
||||
* @param \Drupal\user\UserStorageInterface $user_storage
|
||||
* The user storage.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(PrivateTempStoreFactory $temp_store_factory, UserStorageInterface $user_storage, EntityManagerInterface $entity_manager) {
|
||||
$this->tempStoreFactory = $temp_store_factory;
|
||||
$this->userStorage = $user_storage;
|
||||
$this->entityManager = $entity_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('user.private_tempstore'),
|
||||
$container->get('entity.manager')->getStorage('user'),
|
||||
$container->get('entity.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'user_multiple_cancel_confirm';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Are you sure you want to cancel these user accounts?');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return new Url('entity.user.collection');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Cancel accounts');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
// Retrieve the accounts to be canceled from the temp store.
|
||||
$accounts = $this->tempStoreFactory
|
||||
->get('user_user_operations_cancel')
|
||||
->get($this->currentUser()->id());
|
||||
if (!$accounts) {
|
||||
return $this->redirect('entity.user.collection');
|
||||
}
|
||||
|
||||
$root = NULL;
|
||||
$form['accounts'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
|
||||
foreach ($accounts as $account) {
|
||||
$uid = $account->id();
|
||||
// Prevent user 1 from being canceled.
|
||||
if ($uid <= 1) {
|
||||
$root = intval($uid) === 1 ? $account : $root;
|
||||
continue;
|
||||
}
|
||||
$form['accounts'][$uid] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $uid,
|
||||
'#prefix' => '<li>',
|
||||
'#suffix' => $account->label() . "</li>\n",
|
||||
);
|
||||
}
|
||||
|
||||
// Output a notice that user 1 cannot be canceled.
|
||||
if (isset($root)) {
|
||||
$redirect = (count($accounts) == 1);
|
||||
$message = $this->t('The user account %name cannot be canceled.', array('%name' => $root->label()));
|
||||
drupal_set_message($message, $redirect ? 'error' : 'warning');
|
||||
// If only user 1 was selected, redirect to the overview.
|
||||
if ($redirect) {
|
||||
return $this->redirect('entity.user.collection');
|
||||
}
|
||||
}
|
||||
|
||||
$form['operation'] = array('#type' => 'hidden', '#value' => 'cancel');
|
||||
|
||||
$form['user_cancel_method'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('When cancelling these accounts'),
|
||||
);
|
||||
|
||||
$form['user_cancel_method'] += user_cancel_methods();
|
||||
|
||||
// Allow to send the account cancellation confirmation mail.
|
||||
$form['user_cancel_confirm'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Require email confirmation to cancel account'),
|
||||
'#default_value' => FALSE,
|
||||
'#description' => $this->t('When enabled, the user must confirm the account cancellation via email.'),
|
||||
);
|
||||
// Also allow to send account canceled notification mail, if enabled.
|
||||
$form['user_cancel_notify'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Notify user when account is canceled'),
|
||||
'#default_value' => FALSE,
|
||||
'#access' => $this->config('user.settings')->get('notify.status_canceled'),
|
||||
'#description' => $this->t('When enabled, the user will receive an email notification after the account has been canceled.'),
|
||||
);
|
||||
|
||||
$form = parent::buildForm($form, $form_state);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$current_user_id = $this->currentUser()->id();
|
||||
|
||||
// Clear out the accounts from the temp store.
|
||||
$this->tempStoreFactory->get('user_user_operations_cancel')->delete($current_user_id);
|
||||
if ($form_state->getValue('confirm')) {
|
||||
foreach ($form_state->getValue('accounts') as $uid => $value) {
|
||||
// Prevent programmatic form submissions from cancelling user 1.
|
||||
if ($uid <= 1) {
|
||||
continue;
|
||||
}
|
||||
// Prevent user administrators from deleting themselves without confirmation.
|
||||
if ($uid == $current_user_id) {
|
||||
$admin_form_mock = array();
|
||||
$admin_form_state = $form_state;
|
||||
$admin_form_state->unsetValue('user_cancel_confirm');
|
||||
// The $user global is not a complete user entity, so load the full
|
||||
// entity.
|
||||
$account = $this->userStorage->load($uid);
|
||||
$admin_form = $this->entityManager->getFormObject('user', 'cancel');
|
||||
$admin_form->setEntity($account);
|
||||
// Calling this directly required to init form object with $account.
|
||||
$admin_form->buildForm($admin_form_mock, $admin_form_state);
|
||||
$admin_form->submitForm($admin_form_mock, $admin_form_state);
|
||||
}
|
||||
else {
|
||||
user_cancel($form_state->getValues(), $uid, $form_state->getValue('user_cancel_method'));
|
||||
}
|
||||
}
|
||||
}
|
||||
$form_state->setRedirect('entity.user.collection');
|
||||
}
|
||||
|
||||
}
|
156
core/modules/user/src/Form/UserPasswordForm.php
Normal file
156
core/modules/user/src/Form/UserPasswordForm.php
Normal file
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Form\UserPasswordForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Form;
|
||||
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EmailItem;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Render\Element\Email;
|
||||
use Drupal\user\UserStorageInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a user password reset form.
|
||||
*/
|
||||
class UserPasswordForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\user\UserStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* The language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* Constructs a UserPasswordForm object.
|
||||
*
|
||||
* @param \Drupal\user\UserStorageInterface $user_storage
|
||||
* The user storage.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
*/
|
||||
public function __construct(UserStorageInterface $user_storage, LanguageManagerInterface $language_manager) {
|
||||
$this->userStorage = $user_storage;
|
||||
$this->languageManager = $language_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getStorage('user'),
|
||||
$container->get('language_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'user_pass';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request object.
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Username or email address'),
|
||||
'#size' => 60,
|
||||
'#maxlength' => max(USERNAME_MAX_LENGTH, Email::EMAIL_MAX_LENGTH),
|
||||
'#required' => TRUE,
|
||||
'#attributes' => array(
|
||||
'autocorrect' => 'off',
|
||||
'autocapitalize' => 'off',
|
||||
'spellcheck' => 'false',
|
||||
'autofocus' => 'autofocus',
|
||||
),
|
||||
);
|
||||
// Allow logged in users to request this also.
|
||||
$user = $this->currentUser();
|
||||
if ($user->isAuthenticated()) {
|
||||
$form['name']['#type'] = 'value';
|
||||
$form['name']['#value'] = $user->getEmail();
|
||||
$form['mail'] = array(
|
||||
'#prefix' => '<p>',
|
||||
'#markup' => $this->t('Password reset instructions will be mailed to %email. You must log out to use the password reset link in the email.', array('%email' => $user->getEmail())),
|
||||
'#suffix' => '</p>',
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['mail'] = array(
|
||||
'#prefix' => '<p>',
|
||||
'#markup' => $this->t('Password reset instructions will be sent to your registered e-mail address.'),
|
||||
'#suffix' => '</p>',
|
||||
);
|
||||
$form['name']['#default_value'] = $this->getRequest()->query->get('name');
|
||||
}
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array('#type' => 'submit', '#value' => $this->t('Submit'));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateForm(array &$form, FormStateInterface $form_state) {
|
||||
$name = trim($form_state->getValue('name'));
|
||||
// Try to load by email.
|
||||
$users = $this->userStorage->loadByProperties(array('mail' => $name));
|
||||
if (empty($users)) {
|
||||
// No success, try to load by name.
|
||||
$users = $this->userStorage->loadByProperties(array('name' => $name));
|
||||
}
|
||||
$account = reset($users);
|
||||
if ($account && $account->id()) {
|
||||
// Blocked accounts cannot request a new password.
|
||||
if (!$account->isActive()) {
|
||||
$form_state->setErrorByName('name', $this->t('%name is blocked or has not been activated yet.', array('%name' => $name)));
|
||||
}
|
||||
else {
|
||||
$form_state->setValueForElement(array('#parents' => array('account')), $account);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$form_state->setErrorByName('name', $this->t('Sorry, %name is not recognized as a username or an email address.', array('%name' => $name)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$langcode = $this->languageManager->getCurrentLanguage()->getId();
|
||||
|
||||
$account = $form_state->getValue('account');
|
||||
// Mail one time login URL and instructions using current language.
|
||||
$mail = _user_mail_notify('password_reset', $account, $langcode);
|
||||
if (!empty($mail)) {
|
||||
$this->logger('user')->notice('Password reset instructions mailed to %name at %email.', array('%name' => $account->getUsername(), '%email' => $account->getEmail()));
|
||||
drupal_set_message($this->t('Further instructions have been sent to your email address.'));
|
||||
}
|
||||
|
||||
$form_state->setRedirect('user.page');
|
||||
}
|
||||
|
||||
}
|
123
core/modules/user/src/Form/UserPasswordResetForm.php
Normal file
123
core/modules/user/src/Form/UserPasswordResetForm.php
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Form\UserPasswordResetForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Form controller for the user password forms.
|
||||
*/
|
||||
class UserPasswordResetForm extends FormBase {
|
||||
|
||||
/**
|
||||
* A logger instance.
|
||||
*
|
||||
* @var \Psr\Log\LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* Constructs a new UserPasswordResetForm.
|
||||
*
|
||||
* @param \Psr\Log\LoggerInterface $logger
|
||||
* A logger instance.
|
||||
*/
|
||||
public function __construct(LoggerInterface $logger) {
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('logger.factory')->get('user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'user_pass_reset';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param array $form
|
||||
* An associative array containing the structure of the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
* @param \Drupal\Core\Session\AccountInterface $user
|
||||
* User requesting reset.
|
||||
* @param string $expiration_date
|
||||
* Formatted expiration date for the login link, or NULL if the link does
|
||||
* not expire.
|
||||
* @param int $timestamp
|
||||
* The current timestamp.
|
||||
* @param string $hash
|
||||
* Login link hash.
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, AccountInterface $user = NULL, $expiration_date = NULL, $timestamp = NULL, $hash = NULL) {
|
||||
if ($expiration_date) {
|
||||
$form['message'] = array('#markup' => $this->t('<p>This is a one-time login for %user_name and will expire on %expiration_date.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $user->getUsername(), '%expiration_date' => $expiration_date)));
|
||||
$form['#title'] = $this->t('Reset password');
|
||||
}
|
||||
else {
|
||||
// No expiration for first time login.
|
||||
$form['message'] = array('#markup' => $this->t('<p>This is a one-time login for %user_name.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $user->getUsername())));
|
||||
$form['#title'] = $this->t('Set password');
|
||||
}
|
||||
|
||||
$form['user'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $user,
|
||||
);
|
||||
$form['timestamp'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $timestamp,
|
||||
);
|
||||
$form['help'] = array('#markup' => '<p>' . $this->t('This login can be used only once.') . '</p>');
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Log in'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
/** @var $user \Drupal\user\UserInterface */
|
||||
$user = $form_state->getValue('user');
|
||||
user_login_finalize($user);
|
||||
$this->logger->notice('User %name used one-time login link at time %timestamp.', array('%name' => $user->getUsername(), '%timestamp' => $form_state->getValue('timestamp')));
|
||||
drupal_set_message($this->t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
|
||||
// Let the user's password be changed without the current password check.
|
||||
$token = Crypt::randomBytesBase64(55);
|
||||
$_SESSION['pass_reset_' . $user->id()] = $token;
|
||||
$form_state->setRedirect(
|
||||
'entity.user.edit_form',
|
||||
array('user' => $user->id()),
|
||||
array(
|
||||
'query' => array('pass-reset-token' => $token),
|
||||
'absolute' => TRUE,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
212
core/modules/user/src/Form/UserPermissionsForm.php
Normal file
212
core/modules/user/src/Form/UserPermissionsForm.php
Normal file
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Form\UserPermissionsForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Form;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\user\PermissionHandlerInterface;
|
||||
use Drupal\user\RoleStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides the user permissions administration form.
|
||||
*/
|
||||
class UserPermissionsForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The permission handler.
|
||||
*
|
||||
* @var \Drupal\user\PermissionHandlerInterface
|
||||
*/
|
||||
protected $permissionHandler;
|
||||
|
||||
/**
|
||||
* The role storage.
|
||||
*
|
||||
* @var \Drupal\user\RoleStorageInterface
|
||||
*/
|
||||
protected $roleStorage;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* Constructs a new UserPermissionsForm.
|
||||
*
|
||||
* @param \Drupal\user\PermissionHandlerInterface $permission_handler
|
||||
* The permission handler.
|
||||
* @param \Drupal\user\RoleStorageInterface $role_storage
|
||||
* The role storage.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(PermissionHandlerInterface $permission_handler, RoleStorageInterface $role_storage, ModuleHandlerInterface $module_handler) {
|
||||
$this->permissionHandler = $permission_handler;
|
||||
$this->roleStorage = $role_storage;
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('user.permissions'),
|
||||
$container->get('entity.manager')->getStorage('user_role'),
|
||||
$container->get('module_handler')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'user_admin_permissions';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the roles to display in this form.
|
||||
*
|
||||
* @return \Drupal\user\RoleInterface[]
|
||||
* An array of role objects.
|
||||
*/
|
||||
protected function getRoles() {
|
||||
return $this->roleStorage->loadMultiple();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$role_names = array();
|
||||
$role_permissions = array();
|
||||
$admin_roles = array();
|
||||
foreach ($this->getRoles() as $role_name => $role) {
|
||||
// Retrieve role names for columns.
|
||||
$role_names[$role_name] = SafeMarkup::checkPlain($role->label());
|
||||
// Fetch permissions for the roles.
|
||||
$role_permissions[$role_name] = $role->getPermissions();
|
||||
$admin_roles[$role_name] = $role->isAdmin();
|
||||
}
|
||||
|
||||
// Store $role_names for use when saving the data.
|
||||
$form['role_names'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $role_names,
|
||||
);
|
||||
// Render role/permission overview:
|
||||
$options = array();
|
||||
$hide_descriptions = system_admin_compact_mode();
|
||||
|
||||
$form['system_compact_link'] = array(
|
||||
'#id' => FALSE,
|
||||
'#type' => 'system_compact_link',
|
||||
);
|
||||
|
||||
$form['permissions'] = array(
|
||||
'#type' => 'table',
|
||||
'#header' => array($this->t('Permission')),
|
||||
'#id' => 'permissions',
|
||||
'#attributes' => ['class' => ['permissions', 'js-permissions']],
|
||||
'#sticky' => TRUE,
|
||||
);
|
||||
foreach ($role_names as $name) {
|
||||
$form['permissions']['#header'][] = array(
|
||||
'data' => $name,
|
||||
'class' => array('checkbox'),
|
||||
);
|
||||
}
|
||||
|
||||
$permissions = $this->permissionHandler->getPermissions();
|
||||
$permissions_by_provider = array();
|
||||
foreach ($permissions as $permission_name => $permission) {
|
||||
$permissions_by_provider[$permission['provider']][$permission_name] = $permission;
|
||||
}
|
||||
|
||||
foreach ($permissions_by_provider as $provider => $permissions) {
|
||||
// Module name.
|
||||
$form['permissions'][$provider] = array(array(
|
||||
'#wrapper_attributes' => array(
|
||||
'colspan' => count($role_names) + 1,
|
||||
'class' => array('module'),
|
||||
'id' => 'module-' . $provider,
|
||||
),
|
||||
'#markup' => $this->moduleHandler->getName($provider),
|
||||
));
|
||||
foreach ($permissions as $perm => $perm_item) {
|
||||
// Fill in default values for the permission.
|
||||
$perm_item += array(
|
||||
'description' => '',
|
||||
'restrict access' => FALSE,
|
||||
'warning' => !empty($perm_item['restrict access']) ? $this->t('Warning: Give to trusted roles only; this permission has security implications.') : '',
|
||||
);
|
||||
$options[$perm] = $perm_item['title'];
|
||||
$form['permissions'][$perm]['description'] = array(
|
||||
'#type' => 'inline_template',
|
||||
'#template' => '<div class="permission"><span class="title">{{ title }}</span>{% if description or warning %}<div class="description">{% if warning %}<em class="permission-warning">{{ warning }}</em> {% endif %}{{ description }}</div>{% endif %}</div>',
|
||||
'#context' => array(
|
||||
'title' => $perm_item['title'],
|
||||
),
|
||||
);
|
||||
// Show the permission description.
|
||||
if (!$hide_descriptions) {
|
||||
$form['permissions'][$perm]['description']['#context']['description'] = $perm_item['description'];
|
||||
$form['permissions'][$perm]['description']['#context']['warning'] = $perm_item['warning'];
|
||||
}
|
||||
$options[$perm] = '';
|
||||
foreach ($role_names as $rid => $name) {
|
||||
$form['permissions'][$perm][$rid] = array(
|
||||
'#title' => $name . ': ' . $perm_item['title'],
|
||||
'#title_display' => 'invisible',
|
||||
'#wrapper_attributes' => array(
|
||||
'class' => array('checkbox'),
|
||||
),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => in_array($perm, $role_permissions[$rid]) ? 1 : 0,
|
||||
'#attributes' => array('class' => array('rid-' . $rid, 'js-rid-' . $rid)),
|
||||
'#parents' => array($rid, $perm),
|
||||
);
|
||||
// Show a column of disabled but checked checkboxes.
|
||||
if ($admin_roles[$rid]) {
|
||||
$form['permissions'][$perm][$rid]['#disabled'] = TRUE;
|
||||
$form['permissions'][$perm][$rid]['#default_value'] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Save permissions'),
|
||||
'#button_type' => 'primary',
|
||||
);
|
||||
|
||||
$form['#attached']['library'][] = 'user/drupal.user.permissions';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
foreach ($form_state->getValue('role_names') as $role_name => $name) {
|
||||
user_role_change_permissions($role_name, (array) $form_state->getValue($role_name));
|
||||
}
|
||||
|
||||
drupal_set_message($this->t('The changes have been saved.'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Form\UserPermissionsRoleSpecificForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Form;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Provides the user permissions administration form for a specific role.
|
||||
*/
|
||||
class UserPermissionsRoleSpecificForm extends UserPermissionsForm {
|
||||
|
||||
/**
|
||||
* The specific role for this form.
|
||||
*
|
||||
* @var \Drupal\user\RoleInterface
|
||||
*/
|
||||
protected $userRole;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getRoles() {
|
||||
return array($this->userRole->id() => $this->userRole);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param string $role_id
|
||||
* The user role ID used for this form.
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, RoleInterface $user_role = NULL) {
|
||||
$this->userRole = $user_role;
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
246
core/modules/user/src/PermissionHandler.php
Normal file
246
core/modules/user/src/PermissionHandler.php
Normal file
|
@ -0,0 +1,246 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\PermissionHandler.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Component\Discovery\YamlDiscovery;
|
||||
use Drupal\Core\Controller\ControllerResolverInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
|
||||
/**
|
||||
* Provides the available permissions based on yml files.
|
||||
*
|
||||
* To define permissions you can use a $module.permissions.yml file. This file
|
||||
* defines machine names, human-readable names, restrict access (if required for
|
||||
* security warning), and optionally descriptions for each permission type. The
|
||||
* machine names are the canonical way to refer to permissions for access
|
||||
* checking.
|
||||
*
|
||||
* If your module needs to define dynamic permissions you can use the
|
||||
* permission_callbacks key to declare a callable that will return an array of
|
||||
* permissions, keyed by machine name. Each item in the array can contain the
|
||||
* same keys as an entry in $module.permissions.yml.
|
||||
*
|
||||
* Here is an example from the core filter module (comments have been added):
|
||||
* @code
|
||||
* # The key is the permission machine name, and is required.
|
||||
* administer filters:
|
||||
* # (required) Human readable name of the permission used in the UI.
|
||||
* title: 'Administer text formats and filters'
|
||||
* # (optional) Additional description fo the permission used in the UI.
|
||||
* description: 'Define how text is handled by combining filters into text formats.'
|
||||
* # (optional) Boolean, when set to true a warning about site security will
|
||||
* # be displayed on the Permissions page. Defaults to false.
|
||||
* restrict access: false
|
||||
*
|
||||
* # An array of callables used to generate dynamic permissions.
|
||||
* permission_callbacks:
|
||||
* # Each item in the array should return an associative array with one or
|
||||
* # more permissions following the same keys as the permission defined above.
|
||||
* - Drupal\filter\FilterPermissions::permissions
|
||||
* @endcode
|
||||
*
|
||||
* @see filter.permissions.yml
|
||||
* @see \Drupal\filter\FilterPermissions
|
||||
* @see user_api
|
||||
*/
|
||||
class PermissionHandler implements PermissionHandlerInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The YAML discovery class to find all .permissions.yml files.
|
||||
*
|
||||
* @var \Drupal\Component\Discovery\YamlDiscovery
|
||||
*/
|
||||
protected $yamlDiscovery;
|
||||
|
||||
/**
|
||||
* The controller resolver.
|
||||
*
|
||||
* @var \Drupal\Core\Controller\ControllerResolverInterface
|
||||
*/
|
||||
protected $controllerResolver;
|
||||
|
||||
/**
|
||||
* Constructs a new PermissionHandler.
|
||||
*
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation.
|
||||
* @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver
|
||||
* The controller resolver.
|
||||
*/
|
||||
public function __construct(ModuleHandlerInterface $module_handler, TranslationInterface $string_translation, ControllerResolverInterface $controller_resolver) {
|
||||
// @todo It would be nice if you could pull all module directories from the
|
||||
// container.
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->stringTranslation = $string_translation;
|
||||
$this->controllerResolver = $controller_resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the YAML discovery.
|
||||
*
|
||||
* @return \Drupal\Component\Discovery\YamlDiscovery
|
||||
* The YAML discovery.
|
||||
*/
|
||||
protected function getYamlDiscovery() {
|
||||
if (!isset($this->yamlDiscovery)) {
|
||||
$this->yamlDiscovery = new YamlDiscovery('permissions', $this->moduleHandler->getModuleDirectories());
|
||||
}
|
||||
return $this->yamlDiscovery;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPermissions() {
|
||||
$all_permissions = $this->buildPermissionsYaml();
|
||||
|
||||
return $this->sortPermissions($all_permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function moduleProvidesPermissions($module_name) {
|
||||
// @TODO Static cache this information, see
|
||||
// https://www.drupal.org/node/2339487
|
||||
$permissions = $this->getPermissions();
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
if ($permission['provider'] == $module_name) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds all permissions provided by .permissions.yml files.
|
||||
*
|
||||
* @return array[]
|
||||
* Each return permission is an array with the following keys:
|
||||
* - title: The title of the permission.
|
||||
* - description: The description of the permission, defaults to NULL.
|
||||
* - provider: The provider of the permission.
|
||||
*/
|
||||
protected function buildPermissionsYaml() {
|
||||
$all_permissions = array();
|
||||
$all_callback_permissions = array();
|
||||
|
||||
foreach ($this->getYamlDiscovery()->findAll() as $provider => $permissions) {
|
||||
// The top-level 'permissions_callback' is a list of methods in controller
|
||||
// syntax, see \Drupal\Core\Controller\ControllerResolver. These methods
|
||||
// should return an array of permissions in the same structure.
|
||||
if (isset($permissions['permission_callbacks'])) {
|
||||
foreach ($permissions['permission_callbacks'] as $permission_callback) {
|
||||
$callback = $this->controllerResolver->getControllerFromDefinition($permission_callback);
|
||||
if ($callback_permissions = call_user_func($callback)) {
|
||||
// Add any callback permissions to the array of permissions. Any
|
||||
// defaults can then get processed below.
|
||||
foreach ($callback_permissions as $name => $callback_permission) {
|
||||
if (!is_array($callback_permission)) {
|
||||
$callback_permission = array(
|
||||
'title' => $callback_permission,
|
||||
);
|
||||
}
|
||||
|
||||
$callback_permission += array(
|
||||
'description' => NULL,
|
||||
);
|
||||
$callback_permission['provider'] = $provider;
|
||||
|
||||
$all_callback_permissions[$name] = $callback_permission;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unset($permissions['permission_callbacks']);
|
||||
}
|
||||
|
||||
foreach ($permissions as &$permission) {
|
||||
if (!is_array($permission)) {
|
||||
$permission = array(
|
||||
'title' => $permission,
|
||||
);
|
||||
}
|
||||
$permission['title'] = $this->t($permission['title']);
|
||||
$permission['description'] = isset($permission['description']) ? $this->t($permission['description']) : NULL;
|
||||
$permission['provider'] = $provider;
|
||||
}
|
||||
|
||||
$all_permissions += $permissions;
|
||||
}
|
||||
|
||||
return $all_permissions + $all_callback_permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the given permissions by provider name and title.
|
||||
*
|
||||
* @param array $all_permissions
|
||||
* The permissions to be sorted.
|
||||
*
|
||||
* @return array[]
|
||||
* Each return permission is an array with the following keys:
|
||||
* - title: The title of the permission.
|
||||
* - description: The description of the permission, defaults to NULL.
|
||||
* - provider: The provider of the permission.
|
||||
*/
|
||||
protected function sortPermissions(array $all_permissions = array()) {
|
||||
// Get a list of all the modules providing permissions and sort by
|
||||
// display name.
|
||||
$modules = $this->getModuleNames();
|
||||
|
||||
uasort($all_permissions, function (array $permission_a, array $permission_b) use ($modules) {
|
||||
if ($modules[$permission_a['provider']] == $modules[$permission_b['provider']]) {
|
||||
return $permission_a['title'] > $permission_b['title'];
|
||||
}
|
||||
else {
|
||||
return $modules[$permission_a['provider']] > $modules[$permission_b['provider']];
|
||||
}
|
||||
});
|
||||
return $all_permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all module names.
|
||||
*
|
||||
* @return string[]
|
||||
* Returns the human readable names of all modules keyed by machine name.
|
||||
*/
|
||||
protected function getModuleNames() {
|
||||
$modules = array();
|
||||
foreach (array_keys($this->moduleHandler->getModuleList()) as $module) {
|
||||
$modules[$module] = $this->moduleHandler->getName($module);
|
||||
}
|
||||
asort($modules);
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps system_rebuild_module_data()
|
||||
*
|
||||
* @return \Drupal\Core\Extension\Extension[]
|
||||
*/
|
||||
protected function systemRebuildModuleData() {
|
||||
return system_rebuild_module_data();
|
||||
}
|
||||
|
||||
}
|
58
core/modules/user/src/PermissionHandlerInterface.php
Normal file
58
core/modules/user/src/PermissionHandlerInterface.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\PermissionHandlerInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
/**
|
||||
* Defines an interface to list available permissions.
|
||||
*/
|
||||
interface PermissionHandlerInterface {
|
||||
|
||||
/**
|
||||
* Gets all available permissions.
|
||||
*
|
||||
* @return array
|
||||
* An array whose keys are permission names and whose corresponding values
|
||||
* are arrays containing the following key-value pairs:
|
||||
* - title: The human-readable name of the permission, to be shown on the
|
||||
* permission administration page. This should be wrapped in the t()
|
||||
* function so it can be translated.
|
||||
* - description: (optional) A description of what the permission does. This
|
||||
* should be wrapped in the t() function so it can be translated.
|
||||
* - restrict access: (optional) A boolean which can be set to TRUE to
|
||||
* indicate that site administrators should restrict access to this
|
||||
* permission to trusted users. This should be used for permissions that
|
||||
* have inherent security risks across a variety of potential use cases
|
||||
* (for example, the "administer filters" and "bypass node access"
|
||||
* permissions provided by Drupal core). When set to TRUE, a standard
|
||||
* warning message defined in user_admin_permissions() will be displayed
|
||||
* with the permission on the permission administration page. Defaults
|
||||
* to FALSE.
|
||||
* - warning: (optional) A translated warning message to display for this
|
||||
* permission on the permission administration page. This warning
|
||||
* overrides the automatic warning generated by 'restrict access' being
|
||||
* set to TRUE. This should rarely be used, since it is important for all
|
||||
* permissions to have a clear, consistent security warning that is the
|
||||
* same across the site. Use the 'description' key instead to provide any
|
||||
* information that is specific to the permission you are defining.
|
||||
* - provider: (optional) The provider name of the permission.
|
||||
*/
|
||||
public function getPermissions();
|
||||
|
||||
/**
|
||||
* Determines whether a module provides some permissions.
|
||||
*
|
||||
* @param string $module_name
|
||||
* The module name.
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if the module provides some permissions, otherwise FALSE.
|
||||
*/
|
||||
public function moduleProvidesPermissions($module_name);
|
||||
|
||||
}
|
||||
|
40
core/modules/user/src/Plugin/Action/AddRoleUser.php
Normal file
40
core/modules/user/src/Plugin/Action/AddRoleUser.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Action\AddRoleUser.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\Plugin\Action\ChangeUserRoleBase;
|
||||
|
||||
/**
|
||||
* Adds a role to a user.
|
||||
*
|
||||
* @Action(
|
||||
* id = "user_add_role_action",
|
||||
* label = @Translation("Add a role to the selected users"),
|
||||
* type = "user"
|
||||
* )
|
||||
*/
|
||||
class AddRoleUser extends ChangeUserRoleBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($account = NULL) {
|
||||
$rid = $this->configuration['rid'];
|
||||
// Skip adding the role to the user if they already have it.
|
||||
if ($account !== FALSE && !$account->hasRole($rid)) {
|
||||
// For efficiency manually save the original account before applying
|
||||
// any changes.
|
||||
$account->original = clone $account;
|
||||
$account->addRole($rid);
|
||||
$account->save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
49
core/modules/user/src/Plugin/Action/BlockUser.php
Normal file
49
core/modules/user/src/Plugin/Action/BlockUser.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Action\BlockUser.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\ActionBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Blocks a user.
|
||||
*
|
||||
* @Action(
|
||||
* id = "user_block_user_action",
|
||||
* label = @Translation("Block the selected users"),
|
||||
* type = "user"
|
||||
* )
|
||||
*/
|
||||
class BlockUser extends ActionBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($account = NULL) {
|
||||
// Skip blocking user if they are already blocked.
|
||||
if ($account !== FALSE && $account->isActive()) {
|
||||
// For efficiency manually save the original account before applying any
|
||||
// changes.
|
||||
$account->original = clone $account;
|
||||
$account->block();
|
||||
$account->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
/** @var \Drupal\user\UserInterface $object */
|
||||
$access = $object->status->access('edit', $account, TRUE)
|
||||
->andIf($object->access('update', $account, TRUE));
|
||||
|
||||
return $return_as_object ? $access : $access->isAllowed();
|
||||
}
|
||||
|
||||
}
|
98
core/modules/user/src/Plugin/Action/CancelUser.php
Normal file
98
core/modules/user/src/Plugin/Action/CancelUser.php
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Action\CancelUser.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\ActionBase;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\PrivateTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Cancels a user account.
|
||||
*
|
||||
* @Action(
|
||||
* id = "user_cancel_user_action",
|
||||
* label = @Translation("Cancel the selected user accounts"),
|
||||
* type = "user",
|
||||
* confirm_form_route_name = "user.multiple_cancel_confirm"
|
||||
* )
|
||||
*/
|
||||
class CancelUser extends ActionBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The tempstore factory.
|
||||
*
|
||||
* @var \Drupal\user\PrivateTempStoreFactory
|
||||
*/
|
||||
protected $tempStoreFactory;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Constructs a DeleteNode object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
|
||||
* The tempstore factory.
|
||||
* @param AccountInterface $current_user
|
||||
* Current user.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, PrivateTempStoreFactory $temp_store_factory, AccountInterface $current_user) {
|
||||
$this->currentUser = $current_user;
|
||||
$this->tempStoreFactory = $temp_store_factory;
|
||||
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('user.private_tempstore'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function executeMultiple(array $entities) {
|
||||
$this->tempStoreFactory->get('user_user_operations_cancel')->set($this->currentUser->id(), $entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($object = NULL) {
|
||||
$this->executeMultiple(array($object));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
/** @var \Drupal\user\UserInterface $object */
|
||||
return $object->access('delete', $account, $return_as_object);
|
||||
}
|
||||
|
||||
}
|
107
core/modules/user/src/Plugin/Action/ChangeUserRoleBase.php
Normal file
107
core/modules/user/src/Plugin/Action/ChangeUserRoleBase.php
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Action\ChangeUserRoleBase.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\ConfigurableActionBase;
|
||||
use Drupal\Core\Entity\DependencyTrait;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\RoleInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a base class for operations to change a user's role.
|
||||
*/
|
||||
abstract class ChangeUserRoleBase extends ConfigurableActionBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
use DependencyTrait;
|
||||
|
||||
/**
|
||||
* The user role entity type.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeInterface $entity_type) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->entityType = $entity_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager')->getDefinition('user_role')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return array(
|
||||
'rid' => '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$roles = user_role_names(TRUE);
|
||||
unset($roles[RoleInterface::AUTHENTICATED_ID]);
|
||||
$form['rid'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Role'),
|
||||
'#options' => $roles,
|
||||
'#default_value' => $this->configuration['rid'],
|
||||
'#required' => TRUE,
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->configuration['rid'] = $form_state->getValue('rid');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
if (!empty($this->configuration['rid'])) {
|
||||
$prefix = $this->entityType->getConfigPrefix() . '.';
|
||||
$this->addDependency('config', $prefix . $this->configuration['rid']);
|
||||
}
|
||||
return $this->dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
/** @var \Drupal\user\UserInterface $object */
|
||||
$access = $object->access('update', $account, TRUE)
|
||||
->andIf($object->roles->access('edit', $account, TRUE));
|
||||
|
||||
return $return_as_object ? $access : $access->isAllowed();
|
||||
}
|
||||
|
||||
}
|
40
core/modules/user/src/Plugin/Action/RemoveRoleUser.php
Normal file
40
core/modules/user/src/Plugin/Action/RemoveRoleUser.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Action\RemoveRoleUser.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\Plugin\Action\ChangeUserRoleBase;
|
||||
|
||||
/**
|
||||
* Removes a role from a user.
|
||||
*
|
||||
* @Action(
|
||||
* id = "user_remove_role_action",
|
||||
* label = @Translation("Remove a role from the selected users"),
|
||||
* type = "user"
|
||||
* )
|
||||
*/
|
||||
class RemoveRoleUser extends ChangeUserRoleBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($account = NULL) {
|
||||
$rid = $this->configuration['rid'];
|
||||
// Skip removing the role from the user if they already don't have it.
|
||||
if ($account !== FALSE && $account->hasRole($rid)) {
|
||||
// For efficiency manually save the original account before applying
|
||||
// any changes.
|
||||
$account->original = clone $account;
|
||||
$account->removeRole($rid);
|
||||
$account->save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
46
core/modules/user/src/Plugin/Action/UnblockUser.php
Normal file
46
core/modules/user/src/Plugin/Action/UnblockUser.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Action\UnblockUser.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\ActionBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Unblocks a user.
|
||||
*
|
||||
* @Action(
|
||||
* id = "user_unblock_user_action",
|
||||
* label = @Translation("Unblock the selected users"),
|
||||
* type = "user"
|
||||
* )
|
||||
*/
|
||||
class UnblockUser extends ActionBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($account = NULL) {
|
||||
// Skip unblocking user if they are already unblocked.
|
||||
if ($account !== FALSE && $account->isBlocked()) {
|
||||
$account->activate();
|
||||
$account->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
/** @var \Drupal\user\UserInterface $object */
|
||||
$access = $object->status->access('edit', $account, TRUE)
|
||||
->andIf($object->access('update', $account, TRUE));
|
||||
|
||||
return $return_as_object ? $access : $access->isAllowed();
|
||||
}
|
||||
|
||||
}
|
132
core/modules/user/src/Plugin/Block/UserLoginBlock.php
Normal file
132
core/modules/user/src/Plugin/Block/UserLoginBlock.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Block\UserLoginBlock.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Block;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Routing\RedirectDestinationTrait;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Routing\UrlGeneratorTrait;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Block\BlockBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides a 'User login' block.
|
||||
*
|
||||
* @Block(
|
||||
* id = "user_login_block",
|
||||
* admin_label = @Translation("User login"),
|
||||
* category = @Translation("Forms")
|
||||
* )
|
||||
*/
|
||||
class UserLoginBlock extends BlockBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
use UrlGeneratorTrait;
|
||||
use RedirectDestinationTrait;
|
||||
|
||||
/**
|
||||
* The route match.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* Constructs a new UserLoginBlock instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* The plugin configuration, i.e. an array with configuration values keyed
|
||||
* by configuration option name. The special key 'context' may be used to
|
||||
* initialize the defined contexts by setting it to an array of context
|
||||
* values keyed by context names.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->routeMatch = $route_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('current_route_match')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function blockAccess(AccountInterface $account) {
|
||||
$route_name = $this->routeMatch->getRouteName();
|
||||
if ($account->isAnonymous() && !in_array($route_name, array('user.register', 'user.login', 'user.logout'))) {
|
||||
return AccessResult::allowed()
|
||||
->addCacheContexts(['route', 'user.roles:anonymous']);
|
||||
}
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function build() {
|
||||
$form = \Drupal::formBuilder()->getForm('Drupal\user\Form\UserLoginForm');
|
||||
unset($form['name']['#attributes']['autofocus']);
|
||||
unset($form['name']['#description']);
|
||||
unset($form['pass']['#description']);
|
||||
$form['name']['#size'] = 15;
|
||||
$form['pass']['#size'] = 15;
|
||||
$form['#action'] = $this->url('<current>', [], ['query' => $this->getDestinationArray(), 'external' => FALSE]);
|
||||
// Build action links.
|
||||
$items = array();
|
||||
if (\Drupal::config('user.settings')->get('register') != USER_REGISTER_ADMINISTRATORS_ONLY) {
|
||||
$items['create_account'] = \Drupal::l($this->t('Create new account'), new Url('user.register', array(), array(
|
||||
'attributes' => array(
|
||||
'title' => $this->t('Create a new user account.'),
|
||||
'class' => array('create-account-link'),
|
||||
),
|
||||
)));
|
||||
}
|
||||
$items['request_password'] = \Drupal::l($this->t('Reset your password'), new Url('user.pass', array(), array(
|
||||
'attributes' => array(
|
||||
'title' => $this->t('Send password reset instructions via e-mail.'),
|
||||
'class' => array('request-password-link'),
|
||||
),
|
||||
)));
|
||||
return array(
|
||||
'user_login_form' => $form,
|
||||
'user_links' => array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => $items,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @todo Make cacheable once https://www.drupal.org/node/2351015 lands.
|
||||
*/
|
||||
public function getCacheMaxAge() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
90
core/modules/user/src/Plugin/Condition/UserRole.php
Normal file
90
core/modules/user/src/Plugin/Condition/UserRole.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Condition\UserRole.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Condition;
|
||||
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
|
||||
/**
|
||||
* Provides a 'User Role' condition.
|
||||
*
|
||||
* @Condition(
|
||||
* id = "user_role",
|
||||
* label = @Translation("User Role"),
|
||||
* context = {
|
||||
* "user" = @ContextDefinition("entity:user", label = @Translation("User"))
|
||||
* }
|
||||
* )
|
||||
*
|
||||
*/
|
||||
class UserRole extends ConditionPluginBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$form['roles'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('When the user has the following roles'),
|
||||
'#default_value' => $this->configuration['roles'],
|
||||
'#options' => array_map('\Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names()),
|
||||
'#description' => $this->t('If you select no roles, the condition will evaluate to TRUE for all users.'),
|
||||
);
|
||||
return parent::buildConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function defaultConfiguration() {
|
||||
return array(
|
||||
'roles' => array(),
|
||||
) + parent::defaultConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->configuration['roles'] = array_filter($form_state->getValue('roles'));
|
||||
parent::submitConfigurationForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function summary() {
|
||||
// Use the role labels. They will be sanitized below.
|
||||
$roles = array_intersect_key(user_role_names(), $this->configuration['roles']);
|
||||
if (count($roles) > 1) {
|
||||
$roles = implode(', ', $roles);
|
||||
}
|
||||
else {
|
||||
$roles = reset($roles);
|
||||
}
|
||||
if (!empty($this->configuration['negate'])) {
|
||||
return $this->t('The user is not a member of @roles', array('@roles' => $roles));
|
||||
}
|
||||
else {
|
||||
return $this->t('The user is a member of @roles', array('@roles' => $roles));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function evaluate() {
|
||||
if (empty($this->configuration['roles']) && !$this->isNegated()) {
|
||||
return TRUE;
|
||||
}
|
||||
$user = $this->getContextValue('user');
|
||||
return (bool) array_intersect($this->configuration['roles'], $user->getRoles());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\EntityReferenceSelection\UserSelection.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\EntityReferenceSelection;
|
||||
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Database\Query\SelectInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\RoleInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides specific access control for the user entity type.
|
||||
*
|
||||
* @EntityReferenceSelection(
|
||||
* id = "default:user",
|
||||
* label = @Translation("User selection"),
|
||||
* entity_types = {"user"},
|
||||
* group = "default",
|
||||
* weight = 1
|
||||
* )
|
||||
*/
|
||||
class UserSelection extends SelectionBase {
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $connection;
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\user\UserStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* Constructs a new UserSelection object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler service.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
* @param \Drupal\Core\Database\Connection $connection
|
||||
* The database connection.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user, Connection $connection) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_manager, $module_handler, $current_user);
|
||||
|
||||
$this->connection = $connection;
|
||||
$this->userStorage = $entity_manager->getStorage('user');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('current_user'),
|
||||
$container->get('database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
|
||||
$selection_handler_settings = $this->configuration['handler_settings'];
|
||||
|
||||
// Merge in default values.
|
||||
$selection_handler_settings += array(
|
||||
'filter' => array(
|
||||
'type' => '_none',
|
||||
),
|
||||
'include_anonymous' => TRUE,
|
||||
);
|
||||
|
||||
$form['include_anonymous'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Include the anonymous user.'),
|
||||
'#default_value' => $selection_handler_settings['include_anonymous'],
|
||||
);
|
||||
|
||||
// Add user specific filter options.
|
||||
$form['filter']['type'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Filter by'),
|
||||
'#options' => array(
|
||||
'_none' => $this->t('- None -'),
|
||||
'role' => $this->t('User role'),
|
||||
),
|
||||
'#ajax' => TRUE,
|
||||
'#limit_validation_errors' => array(),
|
||||
'#default_value' => $selection_handler_settings['filter']['type'],
|
||||
);
|
||||
|
||||
$form['filter']['settings'] = array(
|
||||
'#type' => 'container',
|
||||
'#attributes' => array('class' => array('entity_reference-settings')),
|
||||
'#process' => array('_entity_reference_form_process_merge_parent'),
|
||||
);
|
||||
|
||||
if ($selection_handler_settings['filter']['type'] == 'role') {
|
||||
// Merge in default values.
|
||||
$selection_handler_settings['filter'] += array(
|
||||
'role' => NULL,
|
||||
);
|
||||
|
||||
$form['filter']['settings']['role'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Restrict to the selected roles'),
|
||||
'#required' => TRUE,
|
||||
'#options' => array_diff_key(user_role_names(TRUE), array(RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID)),
|
||||
'#default_value' => $selection_handler_settings['filter']['role'],
|
||||
);
|
||||
}
|
||||
|
||||
$form += parent::buildConfigurationForm($form, $form_state);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$query = parent::buildEntityQuery($match, $match_operator);
|
||||
|
||||
// The user entity doesn't have a label column.
|
||||
if (isset($match)) {
|
||||
$query->condition('name', $match, $match_operator);
|
||||
}
|
||||
|
||||
// Filter by role.
|
||||
$handler_settings = $this->configuration['handler_settings'];
|
||||
if (!empty($handler_settings['filter']['role'])) {
|
||||
$query->condition('roles', $handler_settings['filter']['role'], 'IN');
|
||||
}
|
||||
|
||||
// Adding the permission check is sadly insufficient for users: core
|
||||
// requires us to also know about the concept of 'blocked' and 'active'.
|
||||
if (!$this->currentUser->hasPermission('administer users')) {
|
||||
$query->condition('status', 1);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function entityQueryAlter(SelectInterface $query) {
|
||||
// Bail out early if we do not need to match the Anonymous user.
|
||||
$handler_settings = $this->configuration['handler_settings'];
|
||||
if (isset($handler_settings['include_anonymous']) && !$handler_settings['include_anonymous']) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->currentUser->hasPermission('administer users')) {
|
||||
// In addition, if the user is administrator, we need to make sure to
|
||||
// match the anonymous user, that doesn't actually have a name in the
|
||||
// database.
|
||||
$conditions = &$query->conditions();
|
||||
foreach ($conditions as $key => $condition) {
|
||||
if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'users_field_data.name') {
|
||||
// Remove the condition.
|
||||
unset($conditions[$key]);
|
||||
|
||||
// Re-add the condition and a condition on uid = 0 so that we end up
|
||||
// with a query in the form:
|
||||
// WHERE (name LIKE :name) OR (:anonymous_name LIKE :name AND uid = 0)
|
||||
$or = db_or();
|
||||
$or->condition($condition['field'], $condition['value'], $condition['operator']);
|
||||
// Sadly, the Database layer doesn't allow us to build a condition
|
||||
// in the form ':placeholder = :placeholder2', because the 'field'
|
||||
// part of a condition is always escaped.
|
||||
// As a (cheap) workaround, we separately build a condition with no
|
||||
// field, and concatenate the field and the condition separately.
|
||||
$value_part = db_and();
|
||||
$value_part->condition('anonymous_name', $condition['value'], $condition['operator']);
|
||||
$value_part->compile($this->connection, $query);
|
||||
$or->condition(db_and()
|
||||
->where(str_replace('anonymous_name', ':anonymous_name', (string) $value_part), $value_part->arguments() + array(':anonymous_name' => user_format_name($this->userStorage->load(0))))
|
||||
->condition('base_table.uid', 0)
|
||||
);
|
||||
$query->condition($or);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Field\FieldFormatter\AuthorFormatter.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceFormatterBase;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'author' formatter.
|
||||
*
|
||||
* @FieldFormatter(
|
||||
* id = "author",
|
||||
* label = @Translation("Author"),
|
||||
* description = @Translation("Display the referenced author user entity."),
|
||||
* field_types = {
|
||||
* "entity_reference"
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class AuthorFormatter extends EntityReferenceFormatterBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items) {
|
||||
$elements = array();
|
||||
|
||||
foreach ($this->getEntitiesToView($items) as $delta => $entity) {
|
||||
/** @var $referenced_user \Drupal\user\UserInterface */
|
||||
$elements[$delta] = array(
|
||||
'#theme' => 'username',
|
||||
'#account' => $entity,
|
||||
'#link_options' => array('attributes' => array('rel' => 'author')),
|
||||
'#cache' => array(
|
||||
'tags' => $entity->getCacheTags(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function isApplicable(FieldDefinitionInterface $field_definition) {
|
||||
return $field_definition->getFieldStorageDefinition()->getSetting('target_type') == 'user';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity) {
|
||||
// Always allow an entity author's username to be read, even if the current
|
||||
// user does not have permission to view the entity author's profile.
|
||||
return AccessResult::allowed();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Field\FieldFormatter\UserNameFormatter.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Field\FormatterBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Plugin implementation of the 'user_name' formatter.
|
||||
*
|
||||
* @FieldFormatter(
|
||||
* id = "user_name",
|
||||
* label = @Translation("User name"),
|
||||
* description = @Translation("Display the user or author name."),
|
||||
* field_types = {
|
||||
* "string"
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class UserNameFormatter extends FormatterBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function defaultSettings() {
|
||||
$options = parent::defaultSettings();
|
||||
|
||||
$options['link_to_entity'] = TRUE;
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state) {
|
||||
$form = parent::settingsForm($form, $form_state);
|
||||
|
||||
$form['link_to_entity'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Link to the user'),
|
||||
'#default_value' => $this->getSetting('link_to_entity'),
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items) {
|
||||
$elements = [];
|
||||
|
||||
foreach ($items as $delta => $item) {
|
||||
/** @var $user \Drupal\user\UserInterface */
|
||||
if ($user = $item->getEntity()) {
|
||||
if ($this->getSetting('link_to_entity')) {
|
||||
$elements[$delta] = [
|
||||
'#theme' => 'username',
|
||||
'#account' => $user,
|
||||
'#link_options' => ['attributes' => ['rel' => 'user']],
|
||||
'#cache' => [
|
||||
'tags' => $user->getCacheTags(),
|
||||
],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$elements[$delta] = [
|
||||
'#markup' => $user->getUsername(),
|
||||
'#cache' => [
|
||||
'tags' => $user->getCacheTags(),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function isApplicable(FieldDefinitionInterface $field_definition) {
|
||||
return $field_definition->getTargetEntityTypeId() === 'user' && $field_definition->getName() === 'name';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\LanguageNegotiation;
|
||||
|
||||
use Drupal\language\LanguageNegotiationMethodBase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Class for identifying language from the user preferences.
|
||||
*
|
||||
* @LanguageNegotiation(
|
||||
* id = \Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser::METHOD_ID,
|
||||
* weight = -4,
|
||||
* name = @Translation("User"),
|
||||
* description = @Translation("Follow the user's language preference.")
|
||||
* )
|
||||
*/
|
||||
class LanguageNegotiationUser extends LanguageNegotiationMethodBase {
|
||||
|
||||
/**
|
||||
* The language negotiation method id.
|
||||
*/
|
||||
const METHOD_ID = 'language-user';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLangcode(Request $request = NULL) {
|
||||
$langcode = NULL;
|
||||
|
||||
// User preference (only for authenticated users).
|
||||
if ($this->languageManager && $this->currentUser->isAuthenticated()) {
|
||||
$preferred_langcode = $this->currentUser->getPreferredLangcode();
|
||||
$default_langcode = $this->languageManager->getDefaultLanguage()->getId();
|
||||
$languages = $this->languageManager->getLanguages();
|
||||
if (!empty($preferred_langcode) && $preferred_langcode != $default_langcode && isset($languages[$preferred_langcode])) {
|
||||
$langcode = $preferred_langcode;
|
||||
}
|
||||
}
|
||||
|
||||
// No language preference from the user.
|
||||
return $langcode;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\LanguageNegotiation;
|
||||
|
||||
use Drupal\Core\PathProcessor\PathProcessorManager;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Routing\AdminContext;
|
||||
use Drupal\Core\Routing\RouteMatch;
|
||||
use Drupal\Core\Routing\StackedRouteMatchInterface;
|
||||
use Drupal\language\LanguageNegotiationMethodBase;
|
||||
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
|
||||
|
||||
/**
|
||||
* Identifies admin language from the user preferences.
|
||||
*
|
||||
* @LanguageNegotiation(
|
||||
* id = Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUserAdmin::METHOD_ID,
|
||||
* types = {Drupal\Core\Language\LanguageInterface::TYPE_INTERFACE},
|
||||
* weight = -10,
|
||||
* name = @Translation("Account administration pages"),
|
||||
* description = @Translation("Account administration pages language setting.")
|
||||
* )
|
||||
*/
|
||||
class LanguageNegotiationUserAdmin extends LanguageNegotiationMethodBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The language negotiation method id.
|
||||
*/
|
||||
const METHOD_ID = 'language-user-admin';
|
||||
|
||||
/**
|
||||
* The admin context.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\AdminContext
|
||||
*/
|
||||
protected $adminContext;
|
||||
|
||||
/**
|
||||
* The router.
|
||||
*
|
||||
* This is only used when called from an event subscriber, before the request
|
||||
* has been populated with the route info.
|
||||
*
|
||||
* @var \Symfony\Component\Routing\Matcher\UrlMatcherInterface
|
||||
*/
|
||||
protected $router;
|
||||
|
||||
/**
|
||||
* The path processor manager.
|
||||
*
|
||||
* @var \Drupal\Core\PathProcessor\PathProcessorManager
|
||||
*/
|
||||
protected $pathProcessorManager;
|
||||
|
||||
/**
|
||||
* The stacked route match.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\StackedRouteMatchInterface
|
||||
*/
|
||||
protected $stackedRouteMatch;
|
||||
|
||||
/**
|
||||
* Constructs a new LanguageNegotiationUserAdmin instance.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\AdminContext $admin_context
|
||||
* The admin context.
|
||||
* @param \Symfony\Component\Routing\Matcher\UrlMatcherInterface $router
|
||||
* The router.
|
||||
* @param \Drupal\Core\PathProcessor\PathProcessorManager $path_processor_manager
|
||||
* The path processor manager.
|
||||
* @param \Drupal\Core\Routing\StackedRouteMatchInterface $stacked_route_match
|
||||
* The stacked route match.
|
||||
*/
|
||||
public function __construct(AdminContext $admin_context, UrlMatcherInterface $router, PathProcessorManager $path_processor_manager, StackedRouteMatchInterface $stacked_route_match) {
|
||||
$this->adminContext = $admin_context;
|
||||
$this->router = $router;
|
||||
$this->pathProcessorManager = $path_processor_manager;
|
||||
$this->stackedRouteMatch = $stacked_route_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$container->get('router.admin_context'),
|
||||
$container->get('router'),
|
||||
$container->get('path_processor_manager'),
|
||||
$container->get('current_route_match')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLangcode(Request $request = NULL) {
|
||||
$langcode = NULL;
|
||||
|
||||
// User preference (only for administrators).
|
||||
if ($this->currentUser->hasPermission('access administration pages') && ($preferred_admin_langcode = $this->currentUser->getPreferredAdminLangcode(FALSE)) && $this->isAdminPath($request)) {
|
||||
$langcode = $preferred_admin_langcode;
|
||||
}
|
||||
|
||||
// Not an admin, no admin language preference or not on an admin path.
|
||||
return $langcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given path is an administrative one.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* The request object.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the path is administrative, FALSE otherwise.
|
||||
*/
|
||||
protected function isAdminPath(Request $request) {
|
||||
$result = FALSE;
|
||||
if ($request && $this->adminContext) {
|
||||
// If called from an event subscriber, the request may not have the route
|
||||
// object yet (it is still being built), so use the router to look up
|
||||
// based on the path.
|
||||
$route_match = $this->stackedRouteMatch->getRouteMatchFromRequest($request);
|
||||
if ($route_match && !$route_object = $route_match->getRouteObject()) {
|
||||
try {
|
||||
// Process the path as an inbound path. This will remove any language
|
||||
// prefixes and other path components that inbound processing would
|
||||
// clear out, so we can attempt to load the route clearly.
|
||||
$path = $this->pathProcessorManager->processInbound(urldecode(rtrim($request->getPathInfo(), '/')), $request);
|
||||
$attributes = $this->router->match($path);
|
||||
}
|
||||
catch (ResourceNotFoundException $e) {
|
||||
return FALSE;
|
||||
}
|
||||
catch (AccessDeniedHttpException $e) {
|
||||
return FALSE;
|
||||
}
|
||||
$route_object = $attributes[RouteObjectInterface::ROUTE_OBJECT];
|
||||
}
|
||||
$result = $this->adminContext->isAdminRoute($route_object);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
178
core/modules/user/src/Plugin/Search/UserSearch.php
Normal file
178
core/modules/user/src/Plugin/Search/UserSearch.php
Normal file
|
@ -0,0 +1,178 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Search\UserSearch.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Search;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Access\AccessibleInterface;
|
||||
use Drupal\search\Plugin\SearchPluginBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Executes a keyword search for users against the {users} database table.
|
||||
*
|
||||
* @SearchPlugin(
|
||||
* id = "user_search",
|
||||
* title = @Translation("Users")
|
||||
* )
|
||||
*/
|
||||
class UserSearch extends SearchPluginBase implements AccessibleInterface {
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* The entity manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
static public function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$container->get('database'),
|
||||
$container->get('entity.manager'),
|
||||
$container->get('module_handler'),
|
||||
$container->get('current_user'),
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a UserSearch object.
|
||||
*
|
||||
* @param Connection $database
|
||||
* The database connection.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
* @param ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
*/
|
||||
public function __construct(Connection $database, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user, array $configuration, $plugin_id, $plugin_definition) {
|
||||
$this->database = $database;
|
||||
$this->entityManager = $entity_manager;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->currentUser = $current_user;
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
$result = AccessResult::allowedIf(!empty($account) && $account->hasPermission('access user profiles'))->cachePerPermissions();
|
||||
return $return_as_object ? $result : $result->isAllowed();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute() {
|
||||
$results = array();
|
||||
if (!$this->isSearchExecutable()) {
|
||||
return $results;
|
||||
}
|
||||
|
||||
// Process the keywords.
|
||||
$keys = $this->keywords;
|
||||
// Escape for LIKE matching.
|
||||
$keys = $this->database->escapeLike($keys);
|
||||
// Replace wildcards with MySQL/PostgreSQL wildcards.
|
||||
$keys = preg_replace('!\*+!', '%', $keys);
|
||||
|
||||
// Run the query to find matching users.
|
||||
$query = $this->database
|
||||
->select('users_field_data', 'users')
|
||||
->extend('Drupal\Core\Database\Query\PagerSelectExtender');
|
||||
$query->fields('users', array('uid'));
|
||||
$query->condition('default_langcode', 1);
|
||||
if ($this->currentUser->hasPermission('administer users')) {
|
||||
// Administrators can also search in the otherwise private email field,
|
||||
// and they don't need to be restricted to only active users.
|
||||
$query->fields('users', array('mail'));
|
||||
$query->condition($query->orConditionGroup()
|
||||
->condition('name', '%' . $keys . '%', 'LIKE')
|
||||
->condition('mail', '%' . $keys . '%', 'LIKE')
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Regular users can only search via usernames, and we do not show them
|
||||
// blocked accounts.
|
||||
$query->condition('name', '%' . $keys . '%', 'LIKE')
|
||||
->condition('status', 1);
|
||||
}
|
||||
$uids = $query
|
||||
->limit(15)
|
||||
->execute()
|
||||
->fetchCol();
|
||||
$accounts = $this->entityManager->getStorage('user')->loadMultiple($uids);
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$result = array(
|
||||
'title' => $account->getUsername(),
|
||||
'link' => $account->url('canonical', array('absolute' => TRUE)),
|
||||
);
|
||||
if ($this->currentUser->hasPermission('administer users')) {
|
||||
$result['title'] .= ' (' . $account->getEmail() . ')';
|
||||
}
|
||||
$results[] = $result;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHelp() {
|
||||
$help = array('list' => array(
|
||||
'#theme' => 'item_list',
|
||||
'#items' => array(
|
||||
$this->t('User search looks for user names and partial user names. Example: mar would match usernames mar, delmar, and maryjane.'),
|
||||
$this->t('You can use * as a wildcard within your keyword. Example: m*r would match user names mar, delmar, and elementary.'),
|
||||
),
|
||||
));
|
||||
|
||||
return $help;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Validation\Constraint\ProtectedUserFieldConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* Checks if the plain text password is provided for editing a protected field.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "ProtectedUserField",
|
||||
* label = @Translation("Password required for protected field change", context = "Validation")
|
||||
* )
|
||||
*/
|
||||
class ProtectedUserFieldConstraint extends Constraint {
|
||||
|
||||
/**
|
||||
* Violation message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $message = "Your current password is missing or incorrect; it's required to change the %name.";
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Validation\Constraint\ProtectedUserFieldConstraintValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Validation\Constraint;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Session\AccountProxyInterface;
|
||||
use Drupal\user\UserStorageInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
||||
/**
|
||||
* Validates the ProtectedUserFieldConstraint constraint.
|
||||
*/
|
||||
class ProtectedUserFieldConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
|
||||
|
||||
/**
|
||||
* User storage handler.
|
||||
*
|
||||
* @var \Drupal\user\UserStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountProxyInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Constructs the object.
|
||||
*
|
||||
* @param \Drupal\user\UserStorageInterface $user_storage
|
||||
* The user storage handler.
|
||||
* @param \Drupal\Core\Session\AccountProxyInterface $current_user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(UserStorageInterface $user_storage, AccountProxyInterface $current_user) {
|
||||
$this->userStorage = $user_storage;
|
||||
$this->currentUser = $current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity.manager')->getStorage('user'),
|
||||
$container->get('current_user')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($items, Constraint $constraint) {
|
||||
if (!isset($items)) {
|
||||
return;
|
||||
}
|
||||
/* @var \Drupal\Core\Field\FieldItemListInterface $items */
|
||||
$field = $items->getFieldDefinition();
|
||||
|
||||
/* @var \Drupal\user\UserInterface $account */
|
||||
$account = $items->getEntity();
|
||||
if (!isset($account) || !empty($account->_skipProtectedUserFieldConstraint)) {
|
||||
// Looks like we are validating a field not being part of a user, or the
|
||||
// constraint should be skipped, so do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
// Only validate for existing entities and if this is the current user.
|
||||
if (!$account->isNew() && $account->id() == $this->currentUser->id()) {
|
||||
|
||||
/* @var \Drupal\user\UserInterface $account_unchanged */
|
||||
$account_unchanged = $this->userStorage
|
||||
->loadUnchanged($account->id());
|
||||
|
||||
$changed = FALSE;
|
||||
|
||||
// Special case for the password, it being empty means that the existing
|
||||
// password should not be changed, ignore empty password fields.
|
||||
$value = $items->value;
|
||||
if ($field->getName() != 'pass' || !empty($value)) {
|
||||
// Compare the values of the field this is being validated on.
|
||||
$changed = $items->getValue() != $account_unchanged->get($field->getName())->getValue();
|
||||
}
|
||||
if ($changed && (!$account->checkExistingPassword($account_unchanged))) {
|
||||
$this->context->addViolation($constraint->message, array('%name' => $field->getLabel()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Validation\Constraint\UserMailRequired.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Validation\Constraint;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidatorInterface;
|
||||
use Symfony\Component\Validator\ExecutionContextInterface;
|
||||
|
||||
/**
|
||||
* Checks if the user's email address is provided if required.
|
||||
*
|
||||
* The user mail field is NOT required if account originally had no mail set
|
||||
* and the user performing the edit has 'administer users' permission.
|
||||
* This allows users without email address to be edited and deleted.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "UserMailRequired",
|
||||
* label = @Translation("User email required", context = "Validation")
|
||||
* )
|
||||
*/
|
||||
class UserMailRequired extends Constraint implements ConstraintValidatorInterface {
|
||||
|
||||
/**
|
||||
* Violation message. Use the same message as FormValidator.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $message = '!name field is required.';
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Validator\ExecutionContextInterface
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function initialize(ExecutionContextInterface $context) {
|
||||
$this->context = $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validatedBy() {
|
||||
return get_class($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($items, Constraint $constraint) {
|
||||
/** @var \Drupal\Core\Field\FieldItemListInterface $items */
|
||||
/** @var \Drupal\user\UserInterface $account */
|
||||
$account = $items->getEntity();
|
||||
$existing_value = NULL;
|
||||
if ($account->id()) {
|
||||
$account_unchanged = \Drupal::entityManager()
|
||||
->getStorage('user')
|
||||
->loadUnchanged($account->id());
|
||||
$existing_value = $account_unchanged->getEmail();
|
||||
}
|
||||
|
||||
$required = !(!$existing_value && \Drupal::currentUser()->hasPermission('administer users'));
|
||||
|
||||
if ($required && (!isset($items) || $items->isEmpty())) {
|
||||
$this->context->addViolation($this->message, array('!name' => SafeMarkup::placeholder($account->getFieldDefinition('mail')->getLabel())));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Validation\Constraint\UserMailUnique.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* Checks if a user's email address is unique on the site.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "UserMailUnique",
|
||||
* label = @Translation("User email unique", context = "Validation")
|
||||
* )
|
||||
*/
|
||||
class UserMailUnique extends Constraint {
|
||||
|
||||
public $message = 'The email address %value is already taken.';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validatedBy() {
|
||||
return '\Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Validation\Constraint\UserNameConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* Checks if a value is a valid user name.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "UserName",
|
||||
* label = @Translation("User name", context = "Validation"),
|
||||
* )
|
||||
*/
|
||||
class UserNameConstraint extends Constraint {
|
||||
|
||||
public $emptyMessage = 'You must enter a username.';
|
||||
public $spaceBeginMessage = 'The username cannot begin with a space.';
|
||||
public $spaceEndMessage = 'The username cannot end with a space.';
|
||||
public $multipleSpacesMessage = 'The username cannot contain multiple spaces in a row.';
|
||||
public $illegalMessage = 'The username contains an illegal character.';
|
||||
public $tooLongMessage = 'The username %name is too long: it must be %max characters or less.';
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Validation\Constraint\UserNameConstraintValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Validation\Constraint;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
||||
/**
|
||||
* Validates the UserName constraint.
|
||||
*/
|
||||
class UserNameConstraintValidator extends ConstraintValidator {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($items, Constraint $constraint) {
|
||||
if (!isset($items) || !$items->value) {
|
||||
$this->context->addViolation($constraint->emptyMessage);
|
||||
return;
|
||||
}
|
||||
$name = $items->first()->value;
|
||||
if (substr($name, 0, 1) == ' ') {
|
||||
$this->context->addViolation($constraint->spaceBeginMessage);
|
||||
}
|
||||
if (substr($name, -1) == ' ') {
|
||||
$this->context->addViolation($constraint->spaceEndMessage);
|
||||
}
|
||||
if (strpos($name, ' ') !== FALSE) {
|
||||
$this->context->addViolation($constraint->multipleSpacesMessage);
|
||||
}
|
||||
if (preg_match('/[^\x{80}-\x{F7} a-z0-9@_.\'-]/i', $name)
|
||||
|| preg_match(
|
||||
'/[\x{80}-\x{A0}' . // Non-printable ISO-8859-1 + NBSP
|
||||
'\x{AD}' . // Soft-hyphen
|
||||
'\x{2000}-\x{200F}' . // Various space characters
|
||||
'\x{2028}-\x{202F}' . // Bidirectional text overrides
|
||||
'\x{205F}-\x{206F}' . // Various text hinting characters
|
||||
'\x{FEFF}' . // Byte order mark
|
||||
'\x{FF01}-\x{FF60}' . // Full-width latin
|
||||
'\x{FFF9}-\x{FFFD}' . // Replacement characters
|
||||
'\x{0}-\x{1F}]/u', // NULL byte and control characters
|
||||
$name)
|
||||
) {
|
||||
$this->context->addViolation($constraint->illegalMessage);
|
||||
}
|
||||
if (Unicode::strlen($name) > USERNAME_MAX_LENGTH) {
|
||||
$this->context->addViolation($constraint->tooLongMessage, array('%name' => $name, '%max' => USERNAME_MAX_LENGTH));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\Validation\Constraint\UserNameUnique.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* Checks if a user name is unique on the site.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "UserNameUnique",
|
||||
* label = @Translation("User name unique", context = "Validation"),
|
||||
* )
|
||||
*/
|
||||
class UserNameUnique extends Constraint {
|
||||
|
||||
public $message = 'The username %value is already taken.';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validatedBy() {
|
||||
return '\Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator';
|
||||
}
|
||||
}
|
150
core/modules/user/src/Plugin/views/access/Permission.php
Normal file
150
core/modules/user/src/Plugin/views/access/Permission.php
Normal file
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\access\Permission.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\access;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\user\PermissionHandlerInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\access\AccessPluginBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Access plugin that provides permission-based access control.
|
||||
*
|
||||
* @ingroup views_access_plugins
|
||||
*
|
||||
* @ViewsAccess(
|
||||
* id = "perm",
|
||||
* title = @Translation("Permission"),
|
||||
* help = @Translation("Access will be granted to users with the specified permission string.")
|
||||
* )
|
||||
*/
|
||||
class Permission extends AccessPluginBase implements CacheablePluginInterface {
|
||||
|
||||
/**
|
||||
* Overrides Drupal\views\Plugin\Plugin::$usesOptions.
|
||||
*/
|
||||
protected $usesOptions = TRUE;
|
||||
|
||||
/**
|
||||
* The permission handler.
|
||||
*
|
||||
* @var \Drupal\user\PermissionHandlerInterface
|
||||
*/
|
||||
protected $permissionHandler;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* Constructs a Permission object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\user\PermissionHandlerInterface $permission_handler
|
||||
* The permission handler.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, PermissionHandlerInterface $permission_handler, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->permissionHandler = $permission_handler;
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('user.permissions'),
|
||||
$container->get('module_handler')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access(AccountInterface $account) {
|
||||
return $account->hasPermission($this->options['perm']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function alterRouteDefinition(Route $route) {
|
||||
$route->setRequirement('_permission', $this->options['perm']);
|
||||
}
|
||||
|
||||
public function summaryTitle() {
|
||||
$permissions = $this->permissionHandler->getPermissions();
|
||||
if (isset($permissions[$this->options['perm']])) {
|
||||
return $permissions[$this->options['perm']]['title'];
|
||||
}
|
||||
|
||||
return $this->t($this->options['perm']);
|
||||
}
|
||||
|
||||
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['perm'] = array('default' => 'access content');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
// Get list of permissions
|
||||
$perms = [];
|
||||
$permissions = $this->permissionHandler->getPermissions();
|
||||
foreach ($permissions as $perm => $perm_item) {
|
||||
$provider = $perm_item['provider'];
|
||||
$display_name = $this->moduleHandler->getName($provider);
|
||||
$perms[$display_name][$perm] = SafeMarkup::checkPlain(strip_tags($perm_item['title']));
|
||||
}
|
||||
|
||||
$form['perm'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => $perms,
|
||||
'#title' => $this->t('Permission'),
|
||||
'#default_value' => $this->options['perm'],
|
||||
'#description' => $this->t('Only users with the selected permission flag will be able to access this display.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return ['user.permissions'];
|
||||
}
|
||||
|
||||
}
|
164
core/modules/user/src/Plugin/views/access/Role.php
Normal file
164
core/modules/user/src/Plugin/views/access/Role.php
Normal file
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\access\Role.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\access;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\user\RoleStorageInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\access\AccessPluginBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Access plugin that provides role-based access control.
|
||||
*
|
||||
* @ingroup views_access_plugins
|
||||
*
|
||||
* @ViewsAccess(
|
||||
* id = "role",
|
||||
* title = @Translation("Role"),
|
||||
* help = @Translation("Access will be granted to users with any of the specified roles.")
|
||||
* )
|
||||
*/
|
||||
class Role extends AccessPluginBase implements CacheablePluginInterface {
|
||||
|
||||
/**
|
||||
* Overrides Drupal\views\Plugin\Plugin::$usesOptions.
|
||||
*/
|
||||
protected $usesOptions = TRUE;
|
||||
|
||||
/**
|
||||
* The role storage.
|
||||
*
|
||||
* @var \Drupal\user\RoleStorageInterface
|
||||
*/
|
||||
protected $roleStorage;
|
||||
|
||||
/**
|
||||
* Constructs a Role object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\user\RoleStorageInterface $role_storage
|
||||
* The role storage.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, RoleStorageInterface $role_storage) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->roleStorage = $role_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager')->getStorage('user_role')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access(AccountInterface $account) {
|
||||
return array_intersect(array_filter($this->options['role']), $account->getRoles());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function alterRouteDefinition(Route $route) {
|
||||
if ($this->options['role']) {
|
||||
$route->setRequirement('_role', (string) implode('+', $this->options['role']));
|
||||
}
|
||||
}
|
||||
|
||||
public function summaryTitle() {
|
||||
$count = count($this->options['role']);
|
||||
if ($count < 1) {
|
||||
return $this->t('No role(s) selected');
|
||||
}
|
||||
elseif ($count > 1) {
|
||||
return $this->t('Multiple roles');
|
||||
}
|
||||
else {
|
||||
$rids = user_role_names();
|
||||
$rid = reset($this->options['role']);
|
||||
return SafeMarkup::checkPlain($rids[$rid]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['role'] = array('default' => array());
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
$form['role'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Role'),
|
||||
'#default_value' => $this->options['role'],
|
||||
'#options' => array_map('\Drupal\Component\Utility\SafeMarkup::checkPlain', user_role_names()),
|
||||
'#description' => $this->t('Only the checked roles will be able to access this display.'),
|
||||
);
|
||||
}
|
||||
|
||||
public function validateOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
$role = $form_state->getValue(array('access_options', 'role'));
|
||||
$role = array_filter($role);
|
||||
|
||||
if (!$role) {
|
||||
$form_state->setError($form['role'], $this->t('You must select at least one role if type is "by role"'));
|
||||
}
|
||||
|
||||
$form_state->setValue(array('access_options', 'role'), $role);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
$dependencies = parent::calculateDependencies();
|
||||
|
||||
foreach (array_keys($this->options['role']) as $rid) {
|
||||
if ($role = $this->roleStorage->load($rid)) {
|
||||
$dependencies[$role->getConfigDependencyKey()][] = $role->getConfigDependencyName();
|
||||
}
|
||||
}
|
||||
|
||||
return $dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return ['user.roles'];
|
||||
}
|
||||
|
||||
}
|
||||
|
68
core/modules/user/src/Plugin/views/argument/RolesRid.php
Normal file
68
core/modules/user/src/Plugin/views/argument/RolesRid.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\argument\RolesRid.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\argument;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\views\Plugin\views\argument\ManyToOne;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Allow role ID(s) as argument.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @ViewsArgument("user__roles_rid")
|
||||
*/
|
||||
class RolesRid extends ManyToOne {
|
||||
|
||||
/**
|
||||
* The role entity storage
|
||||
*
|
||||
* @var \Drupal\user\RoleStorage
|
||||
*/
|
||||
protected $roleStorage;
|
||||
|
||||
/**
|
||||
* Constructs a \Drupal\user\Plugin\views\argument\RolesRid object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->roleStorage = $entity_manager->getStorage('user_role');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return parent::create($container, $configuration, $plugin_id, $plugin_definition, $container->get('entity.manager'));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function title_query() {
|
||||
$entities = $this->roleStorage->loadMultiple($this->value);
|
||||
$titles = array();
|
||||
foreach ($entities as $entity) {
|
||||
$titles[] = SafeMarkup::checkPlain($entity->label());
|
||||
}
|
||||
return $titles;
|
||||
}
|
||||
|
||||
}
|
68
core/modules/user/src/Plugin/views/argument/Uid.php
Normal file
68
core/modules/user/src/Plugin/views/argument/Uid.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\argument\Uid.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\argument;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\views\Plugin\views\argument\NumericArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Argument handler to accept a user id.
|
||||
*
|
||||
* @ingroup views_argument_handlers
|
||||
*
|
||||
* @ViewsArgument("user_uid")
|
||||
*/
|
||||
class Uid extends NumericArgument {
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* Constructs a Drupal\Component\Plugin\PluginBase object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $storage
|
||||
* The user storage.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $storage) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->storage = $storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static($configuration, $plugin_id, $plugin_definition,
|
||||
$container->get('entity.manager')->getStorage('user'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the behavior of title(). Get the name of the user.
|
||||
*
|
||||
* @return array
|
||||
* A list of usernames.
|
||||
*/
|
||||
public function titleQuery() {
|
||||
return array_map(function($account) {
|
||||
return SafeMarkup::checkPlain($account->label());
|
||||
}, $this->storage->loadMultiple($this->value));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\argument_default\CurrentUser.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\argument_default;
|
||||
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
|
||||
|
||||
/**
|
||||
* Default argument plugin to extract the current user
|
||||
*
|
||||
* This plugin actually has no options so it odes not need to do a great deal.
|
||||
*
|
||||
* @ViewsArgumentDefault(
|
||||
* id = "current_user",
|
||||
* title = @Translation("User ID from logged in user")
|
||||
* )
|
||||
*/
|
||||
class CurrentUser extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
|
||||
|
||||
public function getArgument() {
|
||||
return \Drupal::currentUser()->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return ['user'];
|
||||
}
|
||||
|
||||
}
|
122
core/modules/user/src/Plugin/views/argument_default/User.php
Normal file
122
core/modules/user/src/Plugin/views/argument_default/User.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\argument_default\User.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\argument_default;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\views\Plugin\CacheablePluginInterface;
|
||||
use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Drupal\user\UserInterface;
|
||||
use Drupal\node\NodeInterface;
|
||||
|
||||
/**
|
||||
* Default argument plugin to extract a user from request.
|
||||
*
|
||||
* @ViewsArgumentDefault(
|
||||
* id = "user",
|
||||
* title = @Translation("User ID from route context")
|
||||
* )
|
||||
*/
|
||||
class User extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
|
||||
|
||||
/**
|
||||
* The route match.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteMatchInterface
|
||||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* Constructs a new User instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
*
|
||||
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
|
||||
* The route match.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->routeMatch = $route_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('current_route_match')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['user'] = array('default' => '');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
$form['user'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Also look for a node and use the node author'),
|
||||
'#default_value' => $this->options['user'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getArgument() {
|
||||
|
||||
// If there is a user object in the current route.
|
||||
if ($user = $this->routeMatch->getParameter('user')) {
|
||||
if ($user instanceof UserInterface) {
|
||||
return $user->id();
|
||||
}
|
||||
}
|
||||
|
||||
// If option to use node author; and node in current route.
|
||||
if (!empty($this->options['user']) && $node = $this->routeMatch->getParameter('node')) {
|
||||
if ($node instanceof NodeInterface) {
|
||||
return $node->getOwnerId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCacheable() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return ['url'];
|
||||
}
|
||||
|
||||
}
|
118
core/modules/user/src/Plugin/views/argument_validator/User.php
Normal file
118
core/modules/user/src/Plugin/views/argument_validator/User.php
Normal file
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\argument_validator\User.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\argument_validator;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\views\argument_validator\Entity;
|
||||
|
||||
/**
|
||||
* Validate whether an argument is a valid user.
|
||||
*
|
||||
* This supports either numeric arguments (UID) or strings (username) and
|
||||
* converts either one into the user's UID. This validator also sets the
|
||||
* argument's title to the username.
|
||||
*/
|
||||
class User extends Entity {
|
||||
|
||||
/**
|
||||
* The user storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $userStorage;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_manager);
|
||||
|
||||
$this->userStorage = $entity_manager->getStorage('user');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['restrict_roles'] = array('default' => FALSE);
|
||||
$options['roles'] = array('default' => array());
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
$sanitized_id = ArgumentPluginBase::encodeValidatorId($this->definition['id']);
|
||||
|
||||
$form['restrict_roles'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Restrict user based on role'),
|
||||
'#default_value' => $this->options['restrict_roles'],
|
||||
);
|
||||
|
||||
$form['roles'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Restrict to the selected roles'),
|
||||
'#options' => array_map(array('\Drupal\Component\Utility\SafeMarkup', 'checkPlain'), user_role_names(TRUE)),
|
||||
'#default_value' => $this->options['roles'],
|
||||
'#description' => $this->t('If no roles are selected, users from any role will be allowed.'),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="options[validate][options][' . $sanitized_id . '][restrict_roles]"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitOptionsForm(&$form, FormStateInterface $form_state, &$options = array()) {
|
||||
// filter trash out of the options so we don't store giant unnecessary arrays
|
||||
$options['roles'] = array_filter($options['roles']);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function validateEntity(EntityInterface $entity) {
|
||||
/** @var \Drupal\user\UserInterface $entity */
|
||||
$role_check_success = TRUE;
|
||||
// See if we're filtering users based on roles.
|
||||
if (!empty($this->options['restrict_roles']) && !empty($this->options['roles'])) {
|
||||
$roles = $this->options['roles'];
|
||||
if (!(bool) array_intersect($entity->getRoles(), $roles)) {
|
||||
$role_check_success = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return $role_check_success && parent::validateEntity($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
$dependencies = parent::calculateDependencies();
|
||||
|
||||
foreach ($this->entityManager->getStorage('user_role')->loadMultiple(array_keys($this->options['roles'])) as $role) {
|
||||
$dependencies[$role->getConfigDependencyKey()][] = $role->getConfigDependencyName();
|
||||
}
|
||||
|
||||
return $dependencies;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\argument_validator\UserName.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\argument_validator;
|
||||
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Validates whether a user name is valid.
|
||||
*
|
||||
* @ViewsArgumentValidator(
|
||||
* id = "user_name",
|
||||
* title = @Translation("User name"),
|
||||
* entity_type = "user"
|
||||
* )
|
||||
*/
|
||||
class UserName extends User {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
$entity_type = $this->entityManager->getDefinition('user');
|
||||
|
||||
$form['multiple']['#options'] = array(
|
||||
0 => $this->t('Single name', array('%type' => $entity_type->getLabel())),
|
||||
1 => $this->t('One or more names separated by , or +', array('%type' => $entity_type->getLabel())),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateArgument($argument) {
|
||||
if ($this->multipleCapable && $this->options['multiple']) {
|
||||
// At this point only interested in individual IDs no matter what type,
|
||||
// just splitting by the allowed delimiters.
|
||||
$names = array_filter(preg_split('/[,+ ]/', $argument));
|
||||
}
|
||||
elseif ($argument) {
|
||||
$names = array($argument);
|
||||
}
|
||||
// No specified argument should be invalid.
|
||||
else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$accounts = $this->userStorage->loadByProperties(array('name' => $names));
|
||||
|
||||
// If there are no accounts, return FALSE now. As we will not enter the
|
||||
// loop below otherwise.
|
||||
if (empty($accounts)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Validate each account. If any fails break out and return false.
|
||||
foreach ($accounts as $account) {
|
||||
if (!in_array($account->getUserName(), $names) || !$this->validateEntity($account)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processSummaryArguments(&$args) {
|
||||
// If the validation says the input is an username, we should reverse the
|
||||
// argument so it works for example for generation summary urls.
|
||||
$uids_arg_keys = array_flip($args);
|
||||
|
||||
foreach ($this->userStorage->loadMultiple($args) as $uid => $account) {
|
||||
$args[$uids_arg_keys[$uid]] = $account->label();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
132
core/modules/user/src/Plugin/views/field/Permissions.php
Normal file
132
core/modules/user/src/Plugin/views/field/Permissions.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\field\Permissions.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\field;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\field\PrerenderList;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Field handler to provide a list of permissions.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*
|
||||
* @ViewsField("user_permissions")
|
||||
*/
|
||||
class Permissions extends PrerenderList {
|
||||
|
||||
/**
|
||||
* The role storage.
|
||||
*
|
||||
* @var \Drupal\user\RoleStorageInterface
|
||||
*/
|
||||
protected $roleStorage;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* Constructs a Drupal\Component\Plugin\PluginBase object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
|
||||
* The entity manager
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, ModuleHandlerInterface $module_handler, EntityManagerInterface $entity_manager) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->roleStorage = $entity_manager->getStorage('user_role');
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static($configuration, $plugin_id, $plugin_definition, $container->get('module_handler'), $container->get('entity.manager'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Drupal\views\Plugin\views\field\FieldPluginBase::init().
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$this->additional_fields['uid'] = array('table' => 'users_field_data', 'field' => 'uid');
|
||||
}
|
||||
|
||||
public function query() {
|
||||
$this->addAdditionalFields();
|
||||
$this->field_alias = $this->aliases['uid'];
|
||||
}
|
||||
|
||||
public function preRender(&$values) {
|
||||
$uids = array();
|
||||
$this->items = array();
|
||||
|
||||
$permission_names = \Drupal::service('user.permissions')->getPermissions();
|
||||
|
||||
$rids = array();
|
||||
foreach ($values as $result) {
|
||||
$user_rids = $this->getEntity($result)->getRoles();
|
||||
$uid = $this->getValue($result);
|
||||
|
||||
foreach ($user_rids as $rid) {
|
||||
$rids[$rid][] = $uid;
|
||||
}
|
||||
}
|
||||
|
||||
if ($rids) {
|
||||
$roles = $this->roleStorage->loadMultiple(array_keys($rids));
|
||||
foreach ($rids as $rid => $role_uids) {
|
||||
foreach ($roles[$rid]->getPermissions() as $permission) {
|
||||
foreach ($role_uids as $uid) {
|
||||
$this->items[$uid][$permission]['permission'] = $permission_names[$permission]['title'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($uids as $uid) {
|
||||
if (isset($this->items[$uid])) {
|
||||
ksort($this->items[$uid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function render_item($count, $item) {
|
||||
return $item['permission'];
|
||||
}
|
||||
|
||||
/*
|
||||
protected function documentSelfTokens(&$tokens) {
|
||||
$tokens['[' . $this->options['id'] . '-role' . ']'] = $this->t('The name of the role.');
|
||||
$tokens['[' . $this->options['id'] . '-rid' . ']'] = $this->t('The role ID of the role.');
|
||||
}
|
||||
|
||||
protected function addSelfTokens(&$tokens, $item) {
|
||||
$tokens['[' . $this->options['id'] . '-role' . ']'] = $item['role'];
|
||||
$tokens['[' . $this->options['id'] . '-rid' . ']'] = $item['rid'];
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
115
core/modules/user/src/Plugin/views/field/Roles.php
Normal file
115
core/modules/user/src/Plugin/views/field/Roles.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\field\Roles.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\field;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\field\PrerenderList;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Field handler to provide a list of roles.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*
|
||||
* @ViewsField("user_roles")
|
||||
*/
|
||||
class Roles extends PrerenderList {
|
||||
|
||||
/**
|
||||
* Database Service Object.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* Constructs a Drupal\Component\Plugin\PluginBase object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Database\Connection $database
|
||||
* Database Service Object.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, Connection $database) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static($configuration, $plugin_id, $plugin_definition, $container->get('database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Drupal\views\Plugin\views\field\FieldPluginBase::init().
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$this->additional_fields['uid'] = array('table' => 'users_field_data', 'field' => 'uid');
|
||||
}
|
||||
|
||||
public function query() {
|
||||
$this->addAdditionalFields();
|
||||
$this->field_alias = $this->aliases['uid'];
|
||||
}
|
||||
|
||||
public function preRender(&$values) {
|
||||
$uids = array();
|
||||
$this->items = array();
|
||||
|
||||
foreach ($values as $result) {
|
||||
$uids[] = $this->getValue($result);
|
||||
}
|
||||
|
||||
if ($uids) {
|
||||
$roles = user_roles();
|
||||
$result = $this->database->query('SELECT u.entity_id as uid, u.roles_target_id as rid FROM {user__roles} u WHERE u.entity_id IN ( :uids[] ) AND u.roles_target_id IN ( :rids[] )', array(':uids[]' => $uids, ':rids[]' => array_keys($roles)));
|
||||
foreach ($result as $role) {
|
||||
$this->items[$role->uid][$role->rid]['role'] = SafeMarkup::checkPlain($roles[$role->rid]->label());
|
||||
$this->items[$role->uid][$role->rid]['rid'] = $role->rid;
|
||||
}
|
||||
// Sort the roles for each user by role weight.
|
||||
$ordered_roles = array_flip(array_keys($roles));
|
||||
foreach ($this->items as &$user_roles) {
|
||||
// Create an array of rids that the user has in the role weight order.
|
||||
$sorted_keys = array_intersect_key($ordered_roles, $user_roles);
|
||||
// Merge with the unsorted array of role information which has the
|
||||
// effect of sorting it.
|
||||
$user_roles = array_merge($sorted_keys, $user_roles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function render_item($count, $item) {
|
||||
return $item['role'];
|
||||
}
|
||||
|
||||
protected function documentSelfTokens(&$tokens) {
|
||||
$tokens['[' . $this->options['id'] . '-role' . ']'] = $this->t('The name of the role.');
|
||||
$tokens['[' . $this->options['id'] . '-rid' . ']'] = $this->t('The role machine-name of the role.');
|
||||
}
|
||||
|
||||
protected function addSelfTokens(&$tokens, $item) {
|
||||
if (!empty($item['role'])) {
|
||||
$tokens['[' . $this->options['id'] . '-role' . ']'] = $item['role'];
|
||||
$tokens['[' . $this->options['id'] . '-rid' . ']'] = $item['rid'];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
47
core/modules/user/src/Plugin/views/field/UserBulkForm.php
Normal file
47
core/modules/user/src/Plugin/views/field/UserBulkForm.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\field\UserBulkForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\field;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\system\Plugin\views\field\BulkForm;
|
||||
use Drupal\user\UserInterface;
|
||||
|
||||
/**
|
||||
* Defines a user operations bulk form element.
|
||||
*
|
||||
* @ViewsField("user_bulk_form")
|
||||
*/
|
||||
class UserBulkForm extends BulkForm {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Provide a more useful title to improve the accessibility.
|
||||
*/
|
||||
public function viewsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::viewsForm($form, $form_state);
|
||||
|
||||
if (!empty($this->view->result)) {
|
||||
foreach ($this->view->result as $row_index => $result) {
|
||||
$account = $result->_entity;
|
||||
if ($account instanceof UserInterface) {
|
||||
$form[$this->options['id']][$row_index]['#title'] = $this->t('Update the user %name', array('%name' => $account->label()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function emptySelectedMessage() {
|
||||
return $this->t('No users selected.');
|
||||
}
|
||||
|
||||
}
|
115
core/modules/user/src/Plugin/views/field/UserData.php
Normal file
115
core/modules/user/src/Plugin/views/field/UserData.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\field\UserData.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\field;
|
||||
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\Plugin\views\field\FieldPluginBase;
|
||||
use Drupal\views\ResultRow;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\user\UserDataInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provides access to the user data service.
|
||||
*
|
||||
* @ingroup views_field_handlers
|
||||
*
|
||||
* @see \Drupal\user\UserDataInterface
|
||||
*
|
||||
* @ViewsField("user_data")
|
||||
*/
|
||||
class UserData extends FieldPluginBase {
|
||||
|
||||
/**
|
||||
* Provides the user data service object.
|
||||
*
|
||||
* @var \Drupal\user\UserDataInterface
|
||||
*/
|
||||
protected $userData;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static($configuration, $plugin_id, $plugin_definition, $container->get('user.data'), $container->get('module_handler'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a UserData object.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, UserDataInterface $user_data, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->userData = $user_data;
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
|
||||
$options['data_module'] = array('default' => '');
|
||||
$options['data_name'] = array('default' => '');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
|
||||
parent::buildOptionsForm($form, $form_state);
|
||||
|
||||
$modules = $this->moduleHandler->getModuleList();
|
||||
$names = array();
|
||||
foreach (array_keys($modules) as $name) {
|
||||
$names[$name] = $this->moduleHandler->getName($name);
|
||||
}
|
||||
|
||||
$form['data_module'] = array(
|
||||
'#title' => $this->t('Module name'),
|
||||
'#type' => 'select',
|
||||
'#description' => $this->t('The module which sets this user data.'),
|
||||
'#default_value' => $this->options['data_module'],
|
||||
'#options' => $names,
|
||||
);
|
||||
|
||||
$form['data_name'] = array(
|
||||
'#title' => $this->t('Name'),
|
||||
'#type' => 'textfield',
|
||||
'#description' => $this->t('The name of the data key.'),
|
||||
'#default_value' => $this->options['data_name'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function render(ResultRow $values) {
|
||||
$uid = $this->getValue($values);
|
||||
$data = $this->userData->get($this->options['data_module'], $uid, $this->options['data_name']);
|
||||
|
||||
// Don't sanitize if no value was found.
|
||||
if (isset($data)) {
|
||||
return $this->sanitizeValue($data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
62
core/modules/user/src/Plugin/views/filter/Current.php
Normal file
62
core/modules/user/src/Plugin/views/filter/Current.php
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\filter\Current.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\filter;
|
||||
|
||||
use Drupal\views\Plugin\views\display\DisplayPluginBase;
|
||||
use Drupal\views\ViewExecutable;
|
||||
use Drupal\views\Plugin\views\filter\BooleanOperator;
|
||||
|
||||
/**
|
||||
* Filter handler for the current user.
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @ViewsFilter("user_current")
|
||||
*/
|
||||
class Current extends BooleanOperator {
|
||||
|
||||
/**
|
||||
* Overrides Drupal\views\Plugin\views\filter\BooleanOperator::init().
|
||||
*/
|
||||
public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
|
||||
parent::init($view, $display, $options);
|
||||
|
||||
$this->value_value = $this->t('Is the logged in user');
|
||||
}
|
||||
|
||||
public function query() {
|
||||
$this->ensureMyTable();
|
||||
|
||||
$field = $this->tableAlias . '.' . $this->realField . ' ';
|
||||
$or = db_or();
|
||||
|
||||
if (empty($this->value)) {
|
||||
$or->condition($field, '***CURRENT_USER***', '<>');
|
||||
if ($this->accept_null) {
|
||||
$or->isNull($field);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$or->condition($field, '***CURRENT_USER***', '=');
|
||||
}
|
||||
$this->query->addWhere($this->options['group'], $or);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
$contexts = parent::getCacheContexts();
|
||||
|
||||
// This filter depends on the current user.
|
||||
$contexts[] = 'user';
|
||||
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
}
|
127
core/modules/user/src/Plugin/views/filter/Name.php
Normal file
127
core/modules/user/src/Plugin/views/filter/Name.php
Normal file
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\filter\Name.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\filter;
|
||||
|
||||
use Drupal\Component\Utility\Tags;
|
||||
use Drupal\Core\Entity\Element\EntityAutocomplete;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\user\Entity\User;
|
||||
use Drupal\views\Plugin\views\filter\InOperator;
|
||||
|
||||
/**
|
||||
* Filter handler for usernames.
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @ViewsFilter("user_name")
|
||||
*/
|
||||
class Name extends InOperator {
|
||||
|
||||
protected $alwaysMultiple = TRUE;
|
||||
|
||||
protected function valueForm(&$form, FormStateInterface $form_state) {
|
||||
$users = $this->value ? User::loadMultiple($this->value) : array();
|
||||
$default_value = EntityAutocomplete::getEntityLabels($users);
|
||||
$form['value'] = array(
|
||||
'#type' => 'entity_autocomplete',
|
||||
'#title' => $this->t('Usernames'),
|
||||
'#description' => $this->t('Enter a comma separated list of user names.'),
|
||||
'#target_type' => 'user',
|
||||
'#tags' => TRUE,
|
||||
'#default_value' => $default_value,
|
||||
'#process_default_value' => FALSE,
|
||||
);
|
||||
|
||||
$user_input = $form_state->getUserInput();
|
||||
if ($form_state->get('exposed') && !isset($user_input[$this->options['expose']['identifier']])) {
|
||||
$user_input[$this->options['expose']['identifier']] = $default_value;
|
||||
$form_state->setUserInput($user_input);
|
||||
}
|
||||
}
|
||||
|
||||
protected function valueValidate($form, FormStateInterface $form_state) {
|
||||
$uids = [];
|
||||
if ($values = $form_state->getValue(array('options', 'value'))) {
|
||||
foreach ($values as $value) {
|
||||
$uids[] = $value['target_id'];
|
||||
}
|
||||
sort($uids);
|
||||
}
|
||||
$form_state->setValue(array('options', 'value'), $uids);
|
||||
}
|
||||
|
||||
public function acceptExposedInput($input) {
|
||||
$rc = parent::acceptExposedInput($input);
|
||||
|
||||
if ($rc) {
|
||||
// If we have previously validated input, override.
|
||||
if (isset($this->validated_exposed_input)) {
|
||||
$this->value = $this->validated_exposed_input;
|
||||
}
|
||||
}
|
||||
|
||||
return $rc;
|
||||
}
|
||||
|
||||
public function validateExposed(&$form, FormStateInterface $form_state) {
|
||||
if (empty($this->options['exposed'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->options['expose']['identifier'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$identifier = $this->options['expose']['identifier'];
|
||||
$input = $form_state->getValue($identifier);
|
||||
|
||||
if ($this->options['is_grouped'] && isset($this->options['group_info']['group_items'][$input])) {
|
||||
$this->operator = $this->options['group_info']['group_items'][$input]['operator'];
|
||||
$input = $this->options['group_info']['group_items'][$input]['value'];
|
||||
}
|
||||
|
||||
$uids = [];
|
||||
$values = $form_state->getValue($identifier);
|
||||
if ($values && (!$this->options['is_grouped'] || ($this->options['is_grouped'] && ($input != 'All')))) {
|
||||
foreach ($values as $value) {
|
||||
$uids[] = $value['target_id'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($uids) {
|
||||
$this->validated_exposed_input = $uids;
|
||||
}
|
||||
}
|
||||
|
||||
protected function valueSubmit($form, FormStateInterface $form_state) {
|
||||
// prevent array filter from removing our anonymous user.
|
||||
}
|
||||
|
||||
// Override to do nothing.
|
||||
public function getValueOptions() { }
|
||||
|
||||
public function adminSummary() {
|
||||
// set up $this->valueOptions for the parent summary
|
||||
$this->valueOptions = array();
|
||||
|
||||
if ($this->value) {
|
||||
$result = entity_load_multiple_by_properties('user', array('uid' => $this->value));
|
||||
foreach ($result as $account) {
|
||||
if ($account->id()) {
|
||||
$this->valueOptions[$account->id()] = $account->label();
|
||||
}
|
||||
else {
|
||||
$this->valueOptions[$account->id()] = 'Anonymous'; // Intentionally NOT translated.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::adminSummary();
|
||||
}
|
||||
|
||||
}
|
108
core/modules/user/src/Plugin/views/filter/Permissions.php
Normal file
108
core/modules/user/src/Plugin/views/filter/Permissions.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\filter\Permissions.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\filter;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\user\PermissionHandlerInterface;
|
||||
use Drupal\views\Plugin\views\filter\ManyToOne;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Filter handler for user roles.
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @ViewsFilter("user_permissions")
|
||||
*/
|
||||
class Permissions extends ManyToOne {
|
||||
|
||||
/**
|
||||
* The permission handler.
|
||||
*
|
||||
* @var \Drupal\user\PermissionHandlerInterface
|
||||
*/
|
||||
protected $permissionHandler;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* Constructs a Permissions object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\user\PermissionHandlerInterface $permission_handler
|
||||
* The permission handler.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, PermissionHandlerInterface $permission_handler, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
|
||||
$this->permissionHandler = $permission_handler;
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('user.permissions'),
|
||||
$container->get('module_handler')
|
||||
);
|
||||
}
|
||||
|
||||
public function getValueOptions() {
|
||||
if (!isset($this->valueOptions)) {
|
||||
$permissions = $this->permissionHandler->getPermissions();
|
||||
foreach ($permissions as $perm => $perm_item) {
|
||||
$provider = $perm_item['provider'];
|
||||
$display_name = $this->moduleHandler->getName($provider);
|
||||
$this->valueOptions[$display_name][$perm] = SafeMarkup::checkPlain(strip_tags($perm_item['title']));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $this->valueOptions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Replace the configured permission with a filter by all roles that have this
|
||||
* permission.
|
||||
*/
|
||||
public function query() {
|
||||
// @todo user_role_names() should maybe support multiple permissions.
|
||||
$rids = array();
|
||||
// Get all roles, that have the configured permissions.
|
||||
foreach ($this->value as $permission) {
|
||||
$roles = user_role_names(FALSE, $permission);
|
||||
$rids += array_keys($roles);
|
||||
}
|
||||
$rids = array_unique($rids);
|
||||
$this->value = $rids;
|
||||
|
||||
// $this->value contains the role IDs that have the configured permission.
|
||||
parent::query();
|
||||
}
|
||||
|
||||
}
|
87
core/modules/user/src/Plugin/views/filter/Roles.php
Normal file
87
core/modules/user/src/Plugin/views/filter/Roles.php
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\filter\Roles.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\filter;
|
||||
|
||||
use Drupal\user\RoleInterface;
|
||||
use Drupal\user\RoleStorageInterface;
|
||||
use Drupal\views\Plugin\views\filter\ManyToOne;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Filter handler for user roles.
|
||||
*
|
||||
* @ingroup views_filter_handlers
|
||||
*
|
||||
* @ViewsFilter("user_roles")
|
||||
*/
|
||||
class Roles extends ManyToOne {
|
||||
|
||||
/**
|
||||
* The role storage.
|
||||
*
|
||||
* @var \Drupal\user\RoleStorageInterface
|
||||
*/
|
||||
protected $roleStorage;
|
||||
|
||||
/**
|
||||
* Constructs a Roles object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\user\RoleStorageInterface $role_storage
|
||||
* The role storage.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, RoleStorageInterface $role_storage) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->roleStorage = $role_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity.manager')->getStorage('user_role')
|
||||
);
|
||||
}
|
||||
|
||||
public function getValueOptions() {
|
||||
$this->valueOptions = user_role_names(TRUE);
|
||||
unset($this->valueOptions[RoleInterface::AUTHENTICATED_ID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override empty and not empty operator labels to be clearer for user roles.
|
||||
*/
|
||||
function operators() {
|
||||
$operators = parent::operators();
|
||||
$operators['empty']['title'] = $this->t("Only has the 'authenticated user' role");
|
||||
$operators['not empty']['title'] = $this->t("Has roles in addition to 'authenticated user'");
|
||||
return $operators;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
$dependencies = array();
|
||||
foreach ($this->value as $role_id) {
|
||||
$role = $this->roleStorage->load($role_id);
|
||||
$dependencies[$role->getConfigDependencyKey()][] = $role->getConfigDependencyName();
|
||||
}
|
||||
return $dependencies;
|
||||
}
|
||||
|
||||
}
|
33
core/modules/user/src/Plugin/views/row/UserRow.php
Normal file
33
core/modules/user/src/Plugin/views/row/UserRow.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\row\UserRow.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\row;
|
||||
|
||||
use Drupal\views\Plugin\views\row\EntityRow;
|
||||
|
||||
/**
|
||||
* A row plugin which renders a user.
|
||||
*
|
||||
* @ingroup views_row_plugins
|
||||
*
|
||||
* @ViewsRow(
|
||||
* id = "entity:user",
|
||||
* )
|
||||
*/
|
||||
class UserRow extends EntityRow {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function defineOptions() {
|
||||
$options = parent::defineOptions();
|
||||
$options['view_mode']['default'] = 'full';
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
}
|
81
core/modules/user/src/Plugin/views/wizard/Users.php
Normal file
81
core/modules/user/src/Plugin/views/wizard/Users.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\Plugin\views\wizard\Users.
|
||||
*/
|
||||
|
||||
namespace Drupal\user\Plugin\views\wizard;
|
||||
|
||||
use Drupal\views\Plugin\views\wizard\WizardPluginBase;
|
||||
|
||||
/**
|
||||
* @todo: replace numbers with constants.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests creating user views with the wizard.
|
||||
*
|
||||
* @ViewsWizard(
|
||||
* id = "users",
|
||||
* base_table = "users_field_data",
|
||||
* title = @Translation("Users")
|
||||
* )
|
||||
*/
|
||||
class Users extends WizardPluginBase {
|
||||
|
||||
/**
|
||||
* Set the created column.
|
||||
*/
|
||||
protected $createdColumn = 'created';
|
||||
|
||||
/**
|
||||
* Set default values for the filters.
|
||||
*/
|
||||
protected $filters = array(
|
||||
'status' => array(
|
||||
'value' => TRUE,
|
||||
'table' => 'users_field_data',
|
||||
'field' => 'status',
|
||||
'plugin_id' => 'boolean',
|
||||
'entity_type' => 'user',
|
||||
'entity_field' => 'status',
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Overrides Drupal\views\Plugin\views\wizard\WizardPluginBase::defaultDisplayOptions().
|
||||
*/
|
||||
protected function defaultDisplayOptions() {
|
||||
$display_options = parent::defaultDisplayOptions();
|
||||
|
||||
// Add permission-based access control.
|
||||
$display_options['access']['type'] = 'perm';
|
||||
$display_options['access']['options']['perm'] = 'access user profiles';
|
||||
|
||||
// Remove the default fields, since we are customizing them here.
|
||||
unset($display_options['fields']);
|
||||
|
||||
/* Field: User: Name */
|
||||
$display_options['fields']['name']['id'] = 'name';
|
||||
$display_options['fields']['name']['table'] = 'users_field_data';
|
||||
$display_options['fields']['name']['field'] = 'name';
|
||||
$display_options['fields']['name']['entity_type'] = 'user';
|
||||
$display_options['fields']['name']['entity_field'] = 'name';
|
||||
$display_options['fields']['name']['label'] = '';
|
||||
$display_options['fields']['name']['alter']['alter_text'] = 0;
|
||||
$display_options['fields']['name']['alter']['make_link'] = 0;
|
||||
$display_options['fields']['name']['alter']['absolute'] = 0;
|
||||
$display_options['fields']['name']['alter']['trim'] = 0;
|
||||
$display_options['fields']['name']['alter']['word_boundary'] = 0;
|
||||
$display_options['fields']['name']['alter']['ellipsis'] = 0;
|
||||
$display_options['fields']['name']['alter']['strip_tags'] = 0;
|
||||
$display_options['fields']['name']['alter']['html'] = 0;
|
||||
$display_options['fields']['name']['hide_empty'] = 0;
|
||||
$display_options['fields']['name']['empty_zero'] = 0;
|
||||
$display_options['fields']['name']['plugin_id'] = 'field';
|
||||
|
||||
return $display_options;
|
||||
}
|
||||
|
||||
}
|
216
core/modules/user/src/PrivateTempStore.php
Normal file
216
core/modules/user/src/PrivateTempStore.php
Normal file
|
@ -0,0 +1,216 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\PrivateTempStore.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
||||
use Drupal\Core\Lock\LockBackendInterface;
|
||||
use Drupal\Core\Session\AccountProxyInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* Stores and retrieves temporary data for a given owner.
|
||||
*
|
||||
* A PrivateTempStore can be used to make temporary, non-cache data available
|
||||
* across requests. The data for the PrivateTempStore is stored in one
|
||||
* key/value collection. PrivateTempStore data expires automatically after a
|
||||
* given timeframe.
|
||||
*
|
||||
* The PrivateTempStore is different from a cache, because the data in it is not
|
||||
* yet saved permanently and so it cannot be rebuilt. Typically, the
|
||||
* PrivateTempStore might be used to store work in progress that is later saved
|
||||
* permanently elsewhere, e.g. autosave data, multistep forms, or in-progress
|
||||
* changes to complex configuration that are not ready to be saved.
|
||||
*
|
||||
* The PrivateTempStore differs from the SharedTempStore in that all keys are
|
||||
* ensured to be unique for a particular user and users can never share data. If
|
||||
* you want to be able to share data between users or use it for locking, use
|
||||
* \Drupal\user\SharedTempStore.
|
||||
*/
|
||||
class PrivateTempStore {
|
||||
|
||||
/**
|
||||
* The key/value storage object used for this data.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The lock object used for this data.
|
||||
*
|
||||
* @var \Drupal\Core\Lock\LockBackendInterface
|
||||
*/
|
||||
protected $lockBackend;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountProxyInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\RequestStack
|
||||
*/
|
||||
protected $requestStack;
|
||||
|
||||
/**
|
||||
* The time to live for items in seconds.
|
||||
*
|
||||
* By default, data is stored for one week (604800 seconds) before expiring.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $expire;
|
||||
|
||||
/**
|
||||
* Constructs a new object for accessing data from a key/value store.
|
||||
*
|
||||
* @param KeyValueStoreExpirableInterface $storage
|
||||
* The key/value storage object used for this data. Each storage object
|
||||
* represents a particular collection of data and will contain any number
|
||||
* of key/value pairs.
|
||||
* @param \Drupal\Core\Lock\LockBackendInterface $lockBackend
|
||||
* The lock object used for this data.
|
||||
* @param mixed $owner
|
||||
* The owner key to store along with the data (e.g. a user or session ID).
|
||||
* @param int $expire
|
||||
* The time to live for items, in seconds.
|
||||
*/
|
||||
public function __construct(KeyValueStoreExpirableInterface $storage, LockBackendInterface $lockBackend, AccountProxyInterface $current_user, RequestStack $request_stack, $expire = 604800) {
|
||||
$this->storage = $storage;
|
||||
$this->lockBackend = $lockBackend;
|
||||
$this->currentUser = $current_user;
|
||||
$this->requestStack = $request_stack;
|
||||
$this->expire = $expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from this PrivateTempStore for a given key.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to retrieve.
|
||||
*
|
||||
* @return mixed
|
||||
* The data associated with the key, or NULL if the key does not exist.
|
||||
*/
|
||||
public function get($key) {
|
||||
$key = $this->createkey($key);
|
||||
if (($object = $this->storage->get($key)) && ($object->owner == $this->getOwner())) {
|
||||
return $object->data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a particular key/value pair in this PrivateTempStore.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to store.
|
||||
* @param mixed $value
|
||||
* The data to store.
|
||||
*/
|
||||
public function set($key, $value) {
|
||||
$key = $this->createkey($key);
|
||||
if (!$this->lockBackend->acquire($key)) {
|
||||
$this->lockBackend->wait($key);
|
||||
if (!$this->lockBackend->acquire($key)) {
|
||||
throw new TempStoreException(SafeMarkup::format("Couldn't acquire lock to update item %key in %collection temporary storage.", array(
|
||||
'%key' => $key,
|
||||
'%collection' => $this->storage->getCollectionName(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
$value = (object) array(
|
||||
'owner' => $this->getOwner(),
|
||||
'data' => $value,
|
||||
'updated' => (int) $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME'),
|
||||
);
|
||||
$this->storage->setWithExpire($key, $value, $this->expire);
|
||||
$this->lockBackend->release($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metadata associated with a particular key/value pair.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to store.
|
||||
*
|
||||
* @return mixed
|
||||
* An object with the owner and updated time if the key has a value, or
|
||||
* NULL otherwise.
|
||||
*/
|
||||
public function getMetadata($key) {
|
||||
$key = $this->createkey($key);
|
||||
// Fetch the key/value pair and its metadata.
|
||||
$object = $this->storage->get($key);
|
||||
if ($object) {
|
||||
// Don't keep the data itself in memory.
|
||||
unset($object->data);
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes data from the store for a given key and releases the lock on it.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to delete.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the object was deleted or does not exist, FALSE if it exists but
|
||||
* is not owned by $this->owner.
|
||||
*/
|
||||
public function delete($key) {
|
||||
$key = $this->createkey($key);
|
||||
if (!$object = $this->storage->get($key)) {
|
||||
return TRUE;
|
||||
}
|
||||
elseif ($object->owner != $this->getOwner()) {
|
||||
return FALSE;
|
||||
}
|
||||
if (!$this->lockBackend->acquire($key)) {
|
||||
$this->lockBackend->wait($key);
|
||||
if (!$this->lockBackend->acquire($key)) {
|
||||
throw new TempStoreException(SafeMarkup::format("Couldn't acquire lock to delete item %key from %collection temporary storage.", array(
|
||||
'%key' => $key,
|
||||
'%collection' => $this->storage->getCollectionName(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
$this->storage->delete($key);
|
||||
$this->lockBackend->release($key);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the key is unique for a user.
|
||||
*
|
||||
* @param string $key
|
||||
* The key.
|
||||
*
|
||||
* @return string
|
||||
* The unique key for the user.
|
||||
*/
|
||||
protected function createkey($key) {
|
||||
return $this->getOwner() . ':' . $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current owner based on the current user or the session ID.
|
||||
*
|
||||
* @return string
|
||||
* The owner.
|
||||
*/
|
||||
protected function getOwner() {
|
||||
return $this->currentUser->id() ?: $this->requestStack->getCurrentRequest()->getSession()->getId();
|
||||
}
|
||||
}
|
89
core/modules/user/src/PrivateTempStoreFactory.php
Normal file
89
core/modules/user/src/PrivateTempStoreFactory.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\PrivateTempStoreFactory.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
|
||||
use Drupal\Core\Lock\LockBackendInterface;
|
||||
use Drupal\Core\Session\AccountProxyInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* Creates a PrivateTempStore object for a given collection.
|
||||
*/
|
||||
class PrivateTempStoreFactory {
|
||||
|
||||
/**
|
||||
* The storage factory creating the backend to store the data.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface
|
||||
*/
|
||||
protected $storageFactory;
|
||||
|
||||
/**
|
||||
* The lock object used for this data.
|
||||
*
|
||||
* @var \Drupal\Core\Lock\LockBackendInterface $lockBackend
|
||||
*/
|
||||
protected $lockBackend;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountProxyInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\RequestStack
|
||||
*/
|
||||
protected $requestStack;
|
||||
|
||||
/**
|
||||
* The time to live for items in seconds.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $expire;
|
||||
|
||||
/**
|
||||
* Constructs a Drupal\user\PrivateTempStoreFactory object.
|
||||
*
|
||||
* @param \Drupal\Core\Database\Connection $connection
|
||||
* The connection object used for this data.
|
||||
* @param \Drupal\Core\Lock\LockBackendInterface $lockBackend
|
||||
* The lock object used for this data.
|
||||
* @param int $expire
|
||||
* The time to live for items, in seconds.
|
||||
*/
|
||||
function __construct(KeyValueExpirableFactoryInterface $storage_factory, LockBackendInterface $lockBackend, AccountProxyInterface $current_user, RequestStack $request_stack, $expire = 604800) {
|
||||
$this->storageFactory = $storage_factory;
|
||||
$this->lockBackend = $lockBackend;
|
||||
$this->currentUser = $current_user;
|
||||
$this->requestStack = $request_stack;
|
||||
$this->expire = $expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PrivateTempStore.
|
||||
*
|
||||
* @param string $collection
|
||||
* The collection name to use for this key/value store. This is typically
|
||||
* a shared namespace or module name, e.g. 'views', 'entity', etc.
|
||||
*
|
||||
* @return \Drupal\user\PrivateTempStore
|
||||
* An instance of the key/value store.
|
||||
*/
|
||||
function get($collection) {
|
||||
// Store the data for this collection in the database.
|
||||
$storage = $this->storageFactory->get("user.private_tempstore.$collection");
|
||||
return new PrivateTempStore($storage, $this->lockBackend, $this->currentUser, $this->requestStack, $this->expire);
|
||||
}
|
||||
|
||||
}
|
75
core/modules/user/src/ProfileForm.php
Normal file
75
core/modules/user/src/ProfileForm.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\ProfileForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\Query\QueryFactory;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
|
||||
/**
|
||||
* Form controller for the profile forms.
|
||||
*/
|
||||
class ProfileForm extends AccountForm {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager, QueryFactory $entity_query) {
|
||||
parent::__construct($entity_manager, $language_manager, $entity_query);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
$element = parent::actions($form, $form_state);
|
||||
|
||||
// The user account being edited.
|
||||
$account = $this->entity;
|
||||
|
||||
// The user doing the editing.
|
||||
$user = $this->currentUser();
|
||||
$element['delete']['#type'] = 'submit';
|
||||
$element['delete']['#value'] = $this->t('Cancel account');
|
||||
$element['delete']['#submit'] = array('::editCancelSubmit');
|
||||
$element['delete']['#access'] = $account->id() > 1 && (($account->id() == $user->id() && $user->hasPermission('cancel account')) || $user->hasPermission('administer users'));
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$account = $this->entity;
|
||||
$account->save();
|
||||
$form_state->setValue('uid', $account->id());
|
||||
|
||||
drupal_set_message($this->t('The changes have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a submit handler for the 'Cancel account' button.
|
||||
*/
|
||||
public function editCancelSubmit($form, FormStateInterface $form_state) {
|
||||
$destination = array();
|
||||
$query = $this->getRequest()->query;
|
||||
if ($query->has('destination')) {
|
||||
$destination = array('destination' => $query->get('destination'));
|
||||
$query->remove('destination');
|
||||
}
|
||||
// We redirect from user/%/edit to user/%/cancel to make the tabs disappear.
|
||||
$form_state->setRedirect(
|
||||
'entity.user.cancel_form',
|
||||
array('user' => $this->entity->id()),
|
||||
array('query' => $destination)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
60
core/modules/user/src/ProfileTranslationHandler.php
Normal file
60
core/modules/user/src/ProfileTranslationHandler.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\ProfileTranslationHandler.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\content_translation\ContentTranslationHandler;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Defines the translation handler for users.
|
||||
*/
|
||||
class ProfileTranslationHandler extends ContentTranslationHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function hasPublishedStatus() {
|
||||
// User status has nothing to do with translations visibility.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function hasCreatedTime() {
|
||||
// User creation date has nothing to do with translation creation date.
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function entityFormAlter(array &$form, FormStateInterface $form_state, EntityInterface $entity) {
|
||||
parent::entityFormAlter($form, $form_state, $entity);
|
||||
$form['actions']['submit']['#submit'][] = array($this, 'entityFormSave');
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for ProfileTranslationHandler::entityFormAlter().
|
||||
*
|
||||
* This handles the save action.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityForm::build().
|
||||
*/
|
||||
public function entityFormSave(array $form, FormStateInterface $form_state) {
|
||||
if ($this->getSourceLangcode($form_state)) {
|
||||
$entity = $form_state->getFormObject()->getEntity();
|
||||
// We need a redirect here, otherwise we would get an access denied page
|
||||
// since the current URL would be preserved and we would try to add a
|
||||
// translation for a language that already has a translation.
|
||||
$form_state->setRedirectUrl($entity->urlInfo());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
153
core/modules/user/src/RegisterForm.php
Normal file
153
core/modules/user/src/RegisterForm.php
Normal file
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\RegisterForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Entity\EntityManagerInterface;
|
||||
use Drupal\Core\Entity\Query\QueryFactory;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
|
||||
/**
|
||||
* Form controller for the user register forms.
|
||||
*/
|
||||
class RegisterForm extends AccountForm {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager, QueryFactory $entity_query) {
|
||||
parent::__construct($entity_manager, $language_manager, $entity_query);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$user = $this->currentUser();
|
||||
/** @var \Drupal\user\UserInterface $account */
|
||||
$account = $this->entity;
|
||||
$admin = $user->hasPermission('administer users');
|
||||
// Pass access information to the submit handler. Running an access check
|
||||
// inside the submit function interferes with form processing and breaks
|
||||
// hook_form_alter().
|
||||
$form['administer_users'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $admin,
|
||||
);
|
||||
|
||||
$form['#attached']['library'][] = 'core/drupal.form';
|
||||
|
||||
// For non-admin users, populate the form fields using data from the
|
||||
// browser.
|
||||
if (!$admin) {
|
||||
$form['#attributes']['data-user-info-from-browser'] = TRUE;
|
||||
}
|
||||
|
||||
// Because the user status has security implications, users are blocked by
|
||||
// default when created programmatically and need to be actively activated
|
||||
// if needed. When administrators create users from the user interface,
|
||||
// however, we assume that they should be created as activated by default.
|
||||
if ($admin) {
|
||||
$account->activate();
|
||||
}
|
||||
|
||||
// Start with the default user account fields.
|
||||
$form = parent::form($form, $form_state, $account);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Drupal\Core\Entity\EntityForm::actions().
|
||||
*/
|
||||
protected function actions(array $form, FormStateInterface $form_state) {
|
||||
$element = parent::actions($form, $form_state);
|
||||
$element['submit']['#value'] = $this->t('Create new account');
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$admin = $form_state->getValue('administer_users');
|
||||
|
||||
if (!\Drupal::config('user.settings')->get('verify_mail') || $admin) {
|
||||
$pass = $form_state->getValue('pass');
|
||||
}
|
||||
else {
|
||||
$pass = user_password();
|
||||
}
|
||||
|
||||
// Remove unneeded values.
|
||||
$form_state->cleanValues();
|
||||
|
||||
$form_state->setValue('pass', $pass);
|
||||
$form_state->setValue('init', $form_state->getValue('mail'));
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$account = $this->entity;
|
||||
$pass = $account->getPassword();
|
||||
$admin = $form_state->getValue('administer_users');
|
||||
$notify = !$form_state->isValueEmpty('notify');
|
||||
|
||||
// Save has no return value so this cannot be tested.
|
||||
// Assume save has gone through correctly.
|
||||
$account->save();
|
||||
|
||||
$form_state->set('user', $account);
|
||||
$form_state->setValue('uid', $account->id());
|
||||
|
||||
$this->logger('user')->notice('New user: %name %email.', array('%name' => $form_state->getValue('name'), '%email' => '<' . $form_state->getValue('mail') . '>', 'type' => $account->link($this->t('Edit'), 'edit-form')));
|
||||
|
||||
// Add plain text password into user account to generate mail tokens.
|
||||
$account->password = $pass;
|
||||
|
||||
// New administrative account without notification.
|
||||
if ($admin && !$notify) {
|
||||
drupal_set_message($this->t('Created a new user account for <a href="@url">%name</a>. No email has been sent.', array('@url' => $account->url(), '%name' => $account->getUsername())));
|
||||
}
|
||||
// No email verification required; log in user immediately.
|
||||
elseif (!$admin && !\Drupal::config('user.settings')->get('verify_mail') && $account->isActive()) {
|
||||
_user_mail_notify('register_no_approval_required', $account);
|
||||
user_login_finalize($account);
|
||||
drupal_set_message($this->t('Registration successful. You are now logged in.'));
|
||||
$form_state->setRedirect('<front>');
|
||||
}
|
||||
// No administrator approval required.
|
||||
elseif ($account->isActive() || $notify) {
|
||||
if (!$account->getEmail() && $notify) {
|
||||
drupal_set_message($this->t('The new user <a href="@url">%name</a> was created without an email address, so no welcome message was sent.', array('@url' => $account->url(), '%name' => $account->getUsername())));
|
||||
}
|
||||
else {
|
||||
$op = $notify ? 'register_admin_created' : 'register_no_approval_required';
|
||||
if (_user_mail_notify($op, $account)) {
|
||||
if ($notify) {
|
||||
drupal_set_message($this->t('A welcome message with further instructions has been emailed to the new user <a href="@url">%name</a>.', array('@url' => $account->url(), '%name' => $account->getUsername())));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('A welcome message with further instructions has been sent to your email address.'));
|
||||
$form_state->setRedirect('<front>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Administrator approval required.
|
||||
else {
|
||||
_user_mail_notify('register_pending_approval', $account);
|
||||
drupal_set_message($this->t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, a welcome message with further instructions has been sent to your email address.'));
|
||||
$form_state->setRedirect('<front>');
|
||||
}
|
||||
}
|
||||
}
|
37
core/modules/user/src/RoleAccessControlHandler.php
Normal file
37
core/modules/user/src/RoleAccessControlHandler.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\RoleAccessControlHandler.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Entity\EntityAccessControlHandler;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines the access control handler for the user role entity type.
|
||||
*
|
||||
* @see \Drupal\user\Entity\Role
|
||||
*/
|
||||
class RoleAccessControlHandler extends EntityAccessControlHandler {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
|
||||
switch ($operation) {
|
||||
case 'delete':
|
||||
if ($entity->id() == RoleInterface::ANONYMOUS_ID || $entity->id() == RoleInterface::AUTHENTICATED_ID) {
|
||||
return AccessResult::forbidden();
|
||||
}
|
||||
|
||||
default:
|
||||
return parent::checkAccess($entity, $operation, $langcode, $account);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
74
core/modules/user/src/RoleForm.php
Normal file
74
core/modules/user/src/RoleForm.php
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\RoleForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Form controller for the role entity edit forms.
|
||||
*/
|
||||
class RoleForm extends EntityForm {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
$entity = $this->entity;
|
||||
$form['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Role name'),
|
||||
'#default_value' => $entity->label(),
|
||||
'#size' => 30,
|
||||
'#required' => TRUE,
|
||||
'#maxlength' => 64,
|
||||
'#description' => $this->t('The name for this role. Example: "Moderator", "Editorial board", "Site architect".'),
|
||||
);
|
||||
$form['id'] = array(
|
||||
'#type' => 'machine_name',
|
||||
'#default_value' => $entity->id(),
|
||||
'#required' => TRUE,
|
||||
'#disabled' => !$entity->isNew(),
|
||||
'#size' => 30,
|
||||
'#maxlength' => 64,
|
||||
'#machine_name' => array(
|
||||
'exists' => ['\Drupal\user\Entity\Role', 'load'],
|
||||
),
|
||||
);
|
||||
$form['weight'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $entity->getWeight(),
|
||||
);
|
||||
|
||||
return parent::form($form, $form_state, $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
$entity = $this->entity;
|
||||
|
||||
// Prevent leading and trailing spaces in role names.
|
||||
$entity->set('label', trim($entity->label()));
|
||||
$status = $entity->save();
|
||||
|
||||
$edit_link = $this->entity->link($this->t('Edit'));
|
||||
if ($status == SAVED_UPDATED) {
|
||||
drupal_set_message($this->t('Role %label has been updated.', array('%label' => $entity->label())));
|
||||
$this->logger('user')->notice('Role %label has been updated.', array('%label' => $entity->label(), 'link' => $edit_link));
|
||||
}
|
||||
else {
|
||||
drupal_set_message($this->t('Role %label has been added.', array('%label' => $entity->label())));
|
||||
$this->logger('user')->notice('Role %label has been added.', array('%label' => $entity->label(), 'link' => $edit_link));
|
||||
}
|
||||
$form_state->setRedirect('entity.user_role.collection');
|
||||
}
|
||||
|
||||
}
|
105
core/modules/user/src/RoleInterface.php
Normal file
105
core/modules/user/src/RoleInterface.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\RoleInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a user role entity.
|
||||
*
|
||||
* @ingroup user_api
|
||||
*/
|
||||
interface RoleInterface extends ConfigEntityInterface {
|
||||
|
||||
/**
|
||||
* Role ID for anonymous users; should match what's in the "role" table.
|
||||
*/
|
||||
const ANONYMOUS_ID = AccountInterface::ANONYMOUS_ROLE;
|
||||
|
||||
/**
|
||||
* Role ID for authenticated users; should match what's in the "role" table.
|
||||
*/
|
||||
const AUTHENTICATED_ID = AccountInterface::AUTHENTICATED_ROLE;
|
||||
|
||||
/**
|
||||
* Returns a list of permissions assigned to the role.
|
||||
*
|
||||
* @return array
|
||||
* The permissions assigned to the role.
|
||||
*/
|
||||
public function getPermissions();
|
||||
|
||||
/**
|
||||
* Checks if the role has a permission.
|
||||
*
|
||||
* @param string $permission
|
||||
* The permission to check for.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the role has the permission, FALSE if not.
|
||||
*/
|
||||
public function hasPermission($permission);
|
||||
|
||||
/**
|
||||
* Grant permissions to the role.
|
||||
*
|
||||
* @param string $permission
|
||||
* The permission to grant.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function grantPermission($permission);
|
||||
|
||||
/**
|
||||
* Revokes a permissions from the user role.
|
||||
*
|
||||
* @param string $permission
|
||||
* The permission to revoke.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function revokePermission($permission);
|
||||
|
||||
/**
|
||||
* Indicates that a role has all available permissions.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the role has all permissions.
|
||||
*/
|
||||
public function isAdmin();
|
||||
|
||||
/**
|
||||
* Sets the role to be an admin role.
|
||||
*
|
||||
* @param bool $is_admin
|
||||
* TRUE, if the role should be an admin role.
|
||||
*
|
||||
* return $this
|
||||
*/
|
||||
public function setIsAdmin($is_admin);
|
||||
|
||||
/**
|
||||
* Returns the weight.
|
||||
*
|
||||
* @return int
|
||||
* The weight of this role.
|
||||
*/
|
||||
public function getWeight();
|
||||
|
||||
/**
|
||||
* Sets the weight to the given value.
|
||||
*
|
||||
* @param int $weight
|
||||
* The desired weight.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setWeight($weight);
|
||||
|
||||
}
|
69
core/modules/user/src/RoleListBuilder.php
Normal file
69
core/modules/user/src/RoleListBuilder.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\RoleListBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Config\Entity\DraggableListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
|
||||
/**
|
||||
* Defines a class to build a listing of user role entities.
|
||||
*
|
||||
* @see \Drupal\user\Entity\Role
|
||||
*/
|
||||
class RoleListBuilder extends DraggableListBuilder {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'user_admin_roles_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header['label'] = t('Name');
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $entity) {
|
||||
$row['label'] = $this->getLabel($entity);
|
||||
return $row + parent::buildRow($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultOperations(EntityInterface $entity) {
|
||||
$operations = parent::getDefaultOperations($entity);
|
||||
|
||||
if ($entity->hasLinkTemplate('edit-permissions-form')) {
|
||||
$operations['permissions'] = array(
|
||||
'title' => t('Edit permissions'),
|
||||
'weight' => 20,
|
||||
'url' => $entity->urlInfo('edit-permissions-form'),
|
||||
);
|
||||
}
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
drupal_set_message(t('The role settings have been updated.'));
|
||||
}
|
||||
|
||||
}
|
33
core/modules/user/src/RoleStorage.php
Normal file
33
core/modules/user/src/RoleStorage.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\RoleStorage.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityStorage;
|
||||
|
||||
/**
|
||||
* Controller class for user roles.
|
||||
*/
|
||||
class RoleStorage extends ConfigEntityStorage implements RoleStorageInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isPermissionInRoles($permission, array $rids) {
|
||||
$has_permission = FALSE;
|
||||
foreach ($this->loadMultiple($rids) as $role) {
|
||||
/** @var \Drupal\user\RoleInterface $role */
|
||||
if ($role->isAdmin() || $role->hasPermission($permission)) {
|
||||
$has_permission = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $has_permission;
|
||||
}
|
||||
|
||||
}
|
30
core/modules/user/src/RoleStorageInterface.php
Normal file
30
core/modules/user/src/RoleStorageInterface.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\RoleStorageInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
|
||||
|
||||
/**
|
||||
* Defines an interface for role entity storage classes.
|
||||
*/
|
||||
interface RoleStorageInterface extends ConfigEntityStorageInterface {
|
||||
|
||||
/**
|
||||
* Returns whether a permission is in one of the passed in roles.
|
||||
*
|
||||
* @param string $permission
|
||||
* The permission.
|
||||
* @param array $rids
|
||||
* The list of role IDs to check.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE is the permission is in at least one of the roles. FALSE otherwise.
|
||||
*/
|
||||
public function isPermissionInRoles($permission, array $rids);
|
||||
|
||||
}
|
279
core/modules/user/src/SharedTempStore.php
Normal file
279
core/modules/user/src/SharedTempStore.php
Normal file
|
@ -0,0 +1,279 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\SharedTempStore.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
|
||||
use Drupal\Core\Lock\LockBackendInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* Stores and retrieves temporary data for a given owner.
|
||||
*
|
||||
* A SharedTempStore can be used to make temporary, non-cache data available
|
||||
* across requests. The data for the SharedTempStore is stored in one key/value
|
||||
* collection. SharedTempStore data expires automatically after a given
|
||||
* timeframe.
|
||||
*
|
||||
* The SharedTempStore is different from a cache, because the data in it is not
|
||||
* yet saved permanently and so it cannot be rebuilt. Typically, the
|
||||
* SharedTempStore might be used to store work in progress that is later saved
|
||||
* permanently elsewhere, e.g. autosave data, multistep forms, or in-progress
|
||||
* changes to complex configuration that are not ready to be saved.
|
||||
*
|
||||
* Each SharedTempStore belongs to a particular owner (e.g. a user, session, or
|
||||
* process). Multiple owners may use the same key/value collection, and the
|
||||
* owner is stored along with the key/value pair.
|
||||
*
|
||||
* Every key is unique within the collection, so the SharedTempStore can check
|
||||
* whether a particular key is already set by a different owner. This is
|
||||
* useful for informing one owner that the data is already in use by another;
|
||||
* for example, to let one user know that another user is in the process of
|
||||
* editing certain data, or even to restrict other users from editing it at
|
||||
* the same time. It is the responsibility of the implementation to decide
|
||||
* when and whether one owner can use or update another owner's data.
|
||||
*
|
||||
* If you want to be able to ensure that the data belongs to the current user,
|
||||
* use \Drupal\user\PrivateTempStore.
|
||||
*/
|
||||
class SharedTempStore {
|
||||
|
||||
/**
|
||||
* The key/value storage object used for this data.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
/**
|
||||
* The lock object used for this data.
|
||||
*
|
||||
* @var \Drupal\Core\Lock\LockBackendInterface
|
||||
*/
|
||||
protected $lockBackend;
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\RequestStack
|
||||
*/
|
||||
protected $requestStack;
|
||||
|
||||
/**
|
||||
* The owner key to store along with the data (e.g. a user or session ID).
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $owner;
|
||||
|
||||
/**
|
||||
* The time to live for items in seconds.
|
||||
*
|
||||
* By default, data is stored for one week (604800 seconds) before expiring.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $expire;
|
||||
|
||||
/**
|
||||
* Constructs a new object for accessing data from a key/value store.
|
||||
*
|
||||
* @param KeyValueStoreExpirableInterface $storage
|
||||
* The key/value storage object used for this data. Each storage object
|
||||
* represents a particular collection of data and will contain any number
|
||||
* of key/value pairs.
|
||||
* @param \Drupal\Core\Lock\LockBackendInterface $lockBackend
|
||||
* The lock object used for this data.
|
||||
* @param mixed $owner
|
||||
* The owner key to store along with the data (e.g. a user or session ID).
|
||||
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
|
||||
* The request stack.
|
||||
* @param int $expire
|
||||
* The time to live for items, in seconds.
|
||||
*/
|
||||
public function __construct(KeyValueStoreExpirableInterface $storage, LockBackendInterface $lockBackend, $owner, RequestStack $request_stack, $expire = 604800) {
|
||||
$this->storage = $storage;
|
||||
$this->lockBackend = $lockBackend;
|
||||
$this->owner = $owner;
|
||||
$this->requestStack = $request_stack;
|
||||
$this->expire = $expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from this SharedTempStore for a given key.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to retrieve.
|
||||
*
|
||||
* @return mixed
|
||||
* The data associated with the key, or NULL if the key does not exist.
|
||||
*/
|
||||
public function get($key) {
|
||||
if ($object = $this->storage->get($key)) {
|
||||
return $object->data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a value from this SharedTempStore for a given key.
|
||||
*
|
||||
* Only returns the value if the value is owned by $this->owner.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to retrieve.
|
||||
*
|
||||
* @return mixed
|
||||
* The data associated with the key, or NULL if the key does not exist.
|
||||
*/
|
||||
public function getIfOwner($key) {
|
||||
if (($object = $this->storage->get($key)) && ($object->owner == $this->owner)) {
|
||||
return $object->data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a particular key/value pair only if the key doesn't already exist.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to check and store.
|
||||
* @param mixed $value
|
||||
* The data to store.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the data was set, or FALSE if it already existed.
|
||||
*/
|
||||
public function setIfNotExists($key, $value) {
|
||||
$value = (object) array(
|
||||
'owner' => $this->owner,
|
||||
'data' => $value,
|
||||
'updated' => (int) $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME'),
|
||||
);
|
||||
return $this->storage->setWithExpireIfNotExists($key, $value, $this->expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a particular key/value pair in this SharedTempStore.
|
||||
*
|
||||
* Only stores the given key/value pair if it does not exist yet or is owned
|
||||
* by $this->owner.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to store.
|
||||
* @param mixed $value
|
||||
* The data to store.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the data was set, or FALSE if it already exists and is not owned
|
||||
* by $this->user.
|
||||
*/
|
||||
public function setIfOwner($key, $value) {
|
||||
if ($this->setIfNotExists($key, $value)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (($object = $this->storage->get($key)) && ($object->owner == $this->owner)) {
|
||||
$this->set($key, $value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a particular key/value pair in this SharedTempStore.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to store.
|
||||
* @param mixed $value
|
||||
* The data to store.
|
||||
*/
|
||||
public function set($key, $value) {
|
||||
if (!$this->lockBackend->acquire($key)) {
|
||||
$this->lockBackend->wait($key);
|
||||
if (!$this->lockBackend->acquire($key)) {
|
||||
throw new TempStoreException(SafeMarkup::format("Couldn't acquire lock to update item %key in %collection temporary storage.", array(
|
||||
'%key' => $key,
|
||||
'%collection' => $this->storage->getCollectionName(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
$value = (object) array(
|
||||
'owner' => $this->owner,
|
||||
'data' => $value,
|
||||
'updated' => (int) $this->requestStack->getMasterRequest()->server->get('REQUEST_TIME'),
|
||||
);
|
||||
$this->storage->setWithExpire($key, $value, $this->expire);
|
||||
$this->lockBackend->release($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metadata associated with a particular key/value pair.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to store.
|
||||
*
|
||||
* @return mixed
|
||||
* An object with the owner and updated time if the key has a value, or
|
||||
* NULL otherwise.
|
||||
*/
|
||||
public function getMetadata($key) {
|
||||
// Fetch the key/value pair and its metadata.
|
||||
$object = $this->storage->get($key);
|
||||
if ($object) {
|
||||
// Don't keep the data itself in memory.
|
||||
unset($object->data);
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes data from the store for a given key and releases the lock on it.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to delete.
|
||||
*/
|
||||
public function delete($key) {
|
||||
if (!$this->lockBackend->acquire($key)) {
|
||||
$this->lockBackend->wait($key);
|
||||
if (!$this->lockBackend->acquire($key)) {
|
||||
throw new TempStoreException(SafeMarkup::format("Couldn't acquire lock to delete item %key from %collection temporary storage.", array(
|
||||
'%key' => $key,
|
||||
'%collection' => $this->storage->getCollectionName(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
$this->storage->delete($key);
|
||||
$this->lockBackend->release($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes data from the store for a given key and releases the lock on it.
|
||||
*
|
||||
* Only delete the given key if it is owned by $this->owner.
|
||||
*
|
||||
* @param string $key
|
||||
* The key of the data to delete.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the object was deleted or does not exist, FALSE if it exists but
|
||||
* is not owned by $this->owner.
|
||||
*/
|
||||
public function deleteIfOwner($key) {
|
||||
if (!$object = $this->storage->get($key)) {
|
||||
return TRUE;
|
||||
}
|
||||
elseif ($object->owner == $this->owner) {
|
||||
$this->delete($key);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
93
core/modules/user/src/SharedTempStoreFactory.php
Normal file
93
core/modules/user/src/SharedTempStoreFactory.php
Normal file
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\user\SharedTempStoreFactory.
|
||||
*/
|
||||
|
||||
namespace Drupal\user;
|
||||
|
||||
use Drupal\Component\Serialization\SerializationInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface;
|
||||
use Drupal\Core\Lock\LockBackendInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
|
||||
/**
|
||||
* Creates a shared temporary storage for a collection.
|
||||
*/
|
||||
class SharedTempStoreFactory {
|
||||
|
||||
/**
|
||||
* The storage factory creating the backend to store the data.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueExpirableFactoryInterface
|
||||
*/
|
||||
protected $storageFactory;
|
||||
|
||||
/**
|
||||
* The lock object used for this data.
|
||||
*
|
||||
* @var \Drupal\Core\Lock\LockBackendInterface $lockBackend
|
||||
*/
|
||||
protected $lockBackend;
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\RequestStack
|
||||
*/
|
||||
protected $requestStack;
|
||||
|
||||
/**
|
||||
* The time to live for items in seconds.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $expire;
|
||||
|
||||
/**
|
||||
* Constructs a Drupal\user\SharedTempStoreFactory object.
|
||||
*
|
||||
* @param \Drupal\Core\Database\Connection $connection
|
||||
* The connection object used for this data.
|
||||
* @param \Drupal\Core\Lock\LockBackendInterface $lockBackend
|
||||
* The lock object used for this data.
|
||||
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
|
||||
* The request stack.
|
||||
* @param int $expire
|
||||
* The time to live for items, in seconds.
|
||||
*/
|
||||
function __construct(KeyValueExpirableFactoryInterface $storage_factory, LockBackendInterface $lockBackend, RequestStack $request_stack, $expire = 604800) {
|
||||
$this->storageFactory = $storage_factory;
|
||||
$this->lockBackend = $lockBackend;
|
||||
$this->requestStack = $request_stack;
|
||||
$this->expire = $expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SharedTempStore for the current user or anonymous session.
|
||||
*
|
||||
* @param string $collection
|
||||
* The collection name to use for this key/value store. This is typically
|
||||
* a shared namespace or module name, e.g. 'views', 'entity', etc.
|
||||
* @param mixed $owner
|
||||
* (optional) The owner of this SharedTempStore. By default, the
|
||||
* SharedTempStore is owned by the currently authenticated user, or by the
|
||||
* active anonymous session if no user is logged in.
|
||||
*
|
||||
* @return \Drupal\user\SharedTempStore
|
||||
* An instance of the key/value store.
|
||||
*/
|
||||
function get($collection, $owner = NULL) {
|
||||
// Use the currently authenticated user ID or the active user ID unless
|
||||
// the owner is overridden.
|
||||
if (!isset($owner)) {
|
||||
$owner = \Drupal::currentUser()->id() ?: session_id();
|
||||
}
|
||||
|
||||
// Store the data for this collection in the database.
|
||||
$storage = $this->storageFactory->get("user.shared_tempstore.$collection");
|
||||
return new SharedTempStore($storage, $this->lockBackend, $owner, $this->requestStack, $this->expire);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue