Commit 0b17f26a authored by webchick's avatar webchick

Issue #1479454 by Hugo Wetterberg, galooph, andypost, marcingy, heyrocker,...

Issue #1479454 by Hugo Wetterberg, galooph, andypost, marcingy, heyrocker, larowlan, alexpott, tim.plunkett, fubhy, sun, dawehner: Convert user roles to configurables.
parent 27349905
......@@ -586,8 +586,8 @@ function template_preprocess_block(&$variables) {
function block_user_role_delete($role) {
foreach (entity_load_multiple('block') as $block_id => $block) {
$visibility = $block->get('visibility');
if (isset($visibility['roles']['roles'][$role->rid])) {
unset($visibility['roles']['roles'][$role->rid]);
if (isset($visibility['roles']['roles'][$role->id()])) {
unset($visibility['roles']['roles'][$role->id()]);
$block->set('visibility', $visibility);
$block->save();
}
......
......@@ -367,7 +367,7 @@ public function form($form, &$form_state) {
}
// Per-role visibility.
$role_options = array_map('check_plain', user_roles());
$role_options = array_map('check_plain', user_role_names());
$form['visibility']['role'] = array(
'#type' => 'details',
'#title' => t('Roles'),
......
......@@ -39,7 +39,7 @@ function testCommentLinks() {
// Remove additional user permissions from $this->web_user added by setUp(),
// since this test is limited to anonymous and authenticated roles only.
user_role_delete(key($this->web_user->roles));
entity_delete_multiple('user_role', array(key($this->web_user->roles)));
// Matrix of possible environmental conditions and configuration settings.
// See setEnvironment() for details.
......
......@@ -169,7 +169,7 @@ function filter_admin_format_form($form, &$form_state, $format) {
$form['roles'] = array(
'#type' => 'checkboxes',
'#title' => t('Roles'),
'#options' => array_map('check_plain', user_roles()),
'#options' => array_map('check_plain', user_role_names()),
'#disabled' => $is_fallback,
'#weight' => -10,
);
......
......@@ -398,11 +398,11 @@ function filter_formats_reset() {
function filter_get_roles_by_format($format) {
// Handle the fallback format upfront (all roles have access to this format).
if ($format->format == filter_fallback_format()) {
return user_roles();
return user_role_names();
}
// Do not list any roles if the permission does not exist.
$permission = filter_permission_name($format);
return !empty($permission) ? user_roles(FALSE, $permission) : array();
return !empty($permission) ? user_role_names(FALSE, $permission) : array();
}
/**
......
......@@ -182,7 +182,7 @@ function testFormatRoles() {
$this->assertFalse(in_array($this->disallowed_format->format, array_keys(filter_get_formats_by_role($rid))), 'A text format which a role does not have access to does not appear in the list of formats available to that role.');
// Check that the fallback format is always allowed.
$this->assertEqual(filter_get_roles_by_format(filter_format_load(filter_fallback_format())), user_roles(), 'All roles have access to the fallback format.');
$this->assertEqual(filter_get_roles_by_format(filter_format_load(filter_fallback_format())), user_role_names(), 'All roles have access to the fallback format.');
$this->assertTrue(in_array(filter_fallback_format(), array_keys(filter_get_formats_by_role($rid))), 'The fallback format appears in the list of allowed formats for any role.');
}
......
......@@ -691,11 +691,9 @@ function node_views_analyze(ViewExecutable $view) {
// check for no access control
$access = $display->getOption('access');
if (empty($access['type']) || $access['type'] == 'none') {
$select = db_select('role', 'r');
$select->innerJoin('role_permission', 'p', 'r.rid = p.rid');
$result = $select->fields('r', array('rid'))
->fields('p', array('permission'))
->condition('r.rid', array('anonymous', 'authenticated'), 'IN')
$result = db_select('role_permission', 'p')
->fields('p', array('rid', 'permission'))
->condition('p.rid', array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID), 'IN')
->condition('p.permission', 'access content')
->execute();
......@@ -703,7 +701,7 @@ function node_views_analyze(ViewExecutable $view) {
$role->safe = TRUE;
$roles[$role->rid] = $role;
}
if (!($roles['anonymous']->safe && $roles['authenticated']->safe)) {
if (!($roles[DRUPAL_ANONYMOUS_RID]->safe && $roles[DRUPAL_AUTHENTICATED_RID]->safe)) {
$ret[] = Analyzer::formatMessage(t('Some roles lack permission to access content, but display %display has no access control.', array('%display' => $display->display['display_title'])), 'warning');
}
$filters = $display->getOption('filters');
......
......@@ -509,11 +509,14 @@ protected function drupalCreateUser(array $permissions = array()) {
* (optional) The role ID (machine name). Defaults to a random name.
* @param string $name
* (optional) The label for the role. Defaults to a random string.
* @param integer $weight
* (optional) The weight for the role. Defaults NULL so that entity_create()
* sets the weight to maximum + 1.
*
* @return string
* Role ID of newly created role, or FALSE if role creation failed.
*/
protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NULL) {
protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NULL, $weight = NULL) {
// Generate a random, lowercase machine name if none was passed.
if (!isset($rid)) {
$rid = strtolower($this->randomName(8));
......@@ -529,22 +532,26 @@ protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NUL
}
// Create new role.
$role = new stdClass();
$role->rid = $rid;
$role->name = $name;
$result = user_role_save($role);
$role = entity_create('user_role', array(
'id' => $rid,
'label' => $name,
));
if (!is_null($weight)) {
$role->set('weight', $weight);
}
$result = $role->save();
$this->assertIdentical($result, SAVED_NEW, t('Created role ID @rid with name @name.', array(
'@name' => var_export($role->name, TRUE),
'@rid' => var_export($role->rid, TRUE),
'@name' => var_export($role->label(), TRUE),
'@rid' => var_export($role->id(), TRUE),
)), t('Role'));
if ($result === SAVED_NEW) {
// Grant the specified permissions to the role, if any.
if (!empty($permissions)) {
user_role_grant_permissions($role->rid, $permissions);
user_role_grant_permissions($role->id(), $permissions);
$assigned_permissions = db_query('SELECT permission FROM {role_permission} WHERE rid = :rid', array(':rid' => $role->rid))->fetchCol();
$assigned_permissions = db_query('SELECT permission FROM {role_permission} WHERE rid = :rid', array(':rid' => $role->id()))->fetchCol();
$missing_permissions = array_diff($permissions, $assigned_permissions);
if (!$missing_permissions) {
$this->pass(t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role'));
......@@ -553,7 +560,7 @@ protected function drupalCreateRole(array $permissions, $rid = NULL, $name = NUL
$this->fail(t('Failed to create permissions: @perms', array('@perms' => implode(', ', $missing_permissions))), t('Role'));
}
}
return $role->rid;
return $role->id();
}
else {
return FALSE;
......
......@@ -73,4 +73,19 @@ public function testRoleUpgrade() {
$this->drupalGet('admin/config/people/accounts');
$this->assertFieldByName('user_admin_role', 3);
}
/**
* Tests that roles were converted to config.
*/
public function testRoleUpgradeToConfig() {
$this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
// Check that the 'anonymous' role has been converted to config.
$anonymous = entity_load('user_role', DRUPAL_ANONYMOUS_RID);
$this->assertNotEqual(FALSE, $anonymous, "The 'anonymous' role has been converted to config.");
// Check that the 'authenticated' role has been converted to config.
$authenticated = entity_load('user_role', DRUPAL_AUTHENTICATED_RID);
$this->assertNotEqual(FALSE, $authenticated, "The 'authenticated' role has been converted to config.");
}
}
id: anonymous
label: Anonymous user
weight: 0
id: authenticated
label: Authenticated user
weight: 1
......@@ -129,7 +129,7 @@ public function form(array $form, array &$form_state, EntityInterface $account)
'#access' => $admin,
);
$roles = array_map('check_plain', user_roles(TRUE));
$roles = array_map('check_plain', user_role_names(TRUE));
// The disabled checkbox subelement for the 'authenticated user' role
// must be generated separately and added to the checkboxes element,
// because of a limitation in Form API not supporting a single disabled
......
<?php
/**
* @file
* Contains Drupal\user\Plugin\Core\Entity\Role.
*/
namespace Drupal\user\Plugin\Core\Entity;
use Drupal\Core\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
use Drupal\Core\Config\Entity\ConfigEntityBase;
/**
* Defines the user role entity class.
*
* @Plugin(
* id = "user_role",
* label = @Translation("Role"),
* module = "user",
* controller_class = "Drupal\user\RoleStorageController",
* config_prefix = "user.role",
* entity_keys = {
* "id" = "id",
* "uuid" = "uuid",
* "label" = "label"
* }
* )
*/
class Role extends ConfigEntityBase {
/**
* The machine name of this role.
*
* @var string
*/
public $id;
/**
* The UUID of this role.
*
* @var string
*/
public $uuid;
/**
* The human-readable label of this role.
*
* @var string
*/
public $label;
/**
* The weight of this role in administrative listings.
*
* @var int
*/
public $weight;
}
......@@ -46,7 +46,7 @@ public function summaryTitle() {
return t('Multiple roles');
}
else {
$rids = user_roles();
$rids = user_role_names();
$rid = reset($this->options['role']);
return check_plain($rids[$rid]);
}
......
......@@ -23,16 +23,7 @@
class RolesRid extends ManyToOne {
function title_query() {
$titles = array();
$query = db_select('role', 'r');
$query->addField('r', 'name');
$query->condition('r.rid', $this->value);
$result = $query->execute();
foreach ($result as $term) {
$titles[] = check_plain($term->name);
}
return $titles;
return array(entity_load('user_role', $this->value)->label());
}
}
......@@ -56,7 +56,7 @@ public function buildOptionsForm(&$form, &$form_state) {
$form['roles'] = array(
'#type' => 'checkboxes',
'#title' => t('Restrict to the selected roles'),
'#options' => array_map('check_plain', user_roles(TRUE)),
'#options' => array_map('check_plain', user_role_names(TRUE)),
'#default_value' => $this->options['roles'],
'#description' => t('If no roles are selected, users from any role will be allowed.'),
'#states' => array(
......
......@@ -47,17 +47,26 @@ function pre_render(&$values) {
}
if ($uids) {
$query = db_select('role', 'r');
$query->join('users_roles', 'u', 'u.rid = r.rid');
$query->addField('r', 'name');
$roles = user_roles();
$query = db_select('users_roles', 'u');
$query->fields('u', array('uid', 'rid'));
$query->condition('u.rid', array_keys($roles));
$query->condition('u.uid', $uids);
$query->orderBy('r.name');
$result = $query->execute();
foreach ($result as $role) {
$this->items[$role->uid][$role->rid]['role'] = check_plain($role->name);
$this->items[$role->uid][$role->rid]['role'] = check_plain($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);
}
}
}
......
......@@ -23,7 +23,7 @@
class Roles extends ManyToOne {
function get_value_options() {
$this->value_options = user_roles(TRUE);
$this->value_options = user_role_names(TRUE);
unset($this->value_options[DRUPAL_AUTHENTICATED_RID]);
}
......
<?php
/**
* @file
* Contains Drupal\user\RoleStorageController.
*/
namespace Drupal\user;
use Drupal\Core\Config\Entity\ConfigStorageController;
use Drupal\Core\Entity\EntityInterface;
/**
* Controller class for user roles.
*/
class RoleStorageController extends ConfigStorageController {
/**
* Overrides ConfigStorageController::preSave().
*/
public function preSave(EntityInterface $entity) {
if (!isset($entity->weight) && $roles = entity_load_multiple('user_role')) {
// Set a role weight to make this new role last.
$max = array_reduce($roles, function($max, $entity) {
return $max > $entity->weight ? $max : $entity->weight;
});
$entity->weight = $max + 1;
}
parent::preSave($entity);
}
/**
* Overrides ConfigStorageController::resetCache().
*/
public function resetCache(array $ids = NULL) {
parent::resetCache($ids);
// Clear the user access cache.
drupal_static_reset('user_access');
drupal_static_reset('user_role_permissions');
}
/**
* Overrides ConfigStorageController::postDelete().
*/
protected function postDelete($entities) {
$rids = array_keys($entities);
// Delete permission assignments.
db_delete('role_permission')
->condition('rid', $rids)
->execute();
// Remove the role from all users.
db_delete('users_roles')
->condition('rid', $rids)
->execute();
}
/**
* Overrides ConfigStorageController::attachLoad().
*/
protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
// Sort the queried roles by their weight.
uasort($queried_entities, 'Drupal\Core\Config\Entity\ConfigEntityBase::sort');
parent::attachLoad($queried_entities, $revision_id);
}
}
......@@ -37,10 +37,10 @@ function testRoleAdministration() {
// correspond to an integer, to test that the role administration pages
// correctly distinguish between role names and IDs.)
$role_name = '123';
$edit = array('role[name]' => $role_name, 'role[rid]' => $role_name);
$edit = array('role[label]' => $role_name, 'role[id]' => $role_name);
$this->drupalPost('admin/people/roles', $edit, t('Add role'));
$this->assertText(t('The role has been added.'), 'The role has been added.');
$role = user_role_load($role_name);
$role = entity_load('user_role', $role_name);
$this->assertTrue(is_object($role), 'The role was successfully retrieved from the database.');
// Try adding a duplicate role.
......@@ -50,18 +50,18 @@ function testRoleAdministration() {
// Test renaming a role.
$old_name = $role_name;
$role_name = '456';
$edit = array('role[name]' => $role_name);
$this->drupalPost("admin/people/roles/edit/{$role->rid}", $edit, t('Save role'));
$edit = array('role[label]' => $role_name);
$this->drupalPost("admin/people/roles/edit/{$role->id()}", $edit, t('Save role'));
$this->assertText(t('The role has been renamed.'), 'The role has been renamed.');
$new_role = user_role_load($old_name);
$this->assertEqual($new_role->name, $role_name, 'The role name has been successfully changed.');
$new_role = entity_load('user_role', $old_name);
$this->assertEqual($new_role->label(), $role_name, 'The role name has been successfully changed.');
// Test deleting a role.
$this->drupalPost("admin/people/roles/edit/{$role->rid}", NULL, t('Delete role'));
$this->drupalPost("admin/people/roles/edit/{$role->id()}", NULL, t('Delete role'));
$this->drupalPost(NULL, NULL, t('Delete'));
$this->assertText(t('The role has been deleted.'), 'The role has been deleted');
$this->assertNoLinkByHref("admin/people/roles/edit/{$role->rid}", 'Role edit link removed.');
$this->assertFalse(user_role_load($role_name), 'A deleted role can no longer be loaded.');
$this->assertNoLinkByHref("admin/people/roles/edit/{$role->id()}", 'Role edit link removed.');
$this->assertFalse(entity_load('user_role', $role_name), 'A deleted role can no longer be loaded.');
// Make sure that the system-defined roles can be edited via the user
// interface.
......@@ -74,24 +74,36 @@ function testRoleAdministration() {
}
/**
* Test user role weight change operation.
* Test user role weight change operation and ordering.
*/
function testRoleWeightChange() {
function testRoleWeightOrdering() {
$this->drupalLogin($this->admin_user);
// Pick up a random role and get its weight.
$rid = array_rand(user_roles());
$role = user_role_load($rid);
$old_weight = $role->weight;
// Change the role weight and submit the form.
$edit = array('roles['. $rid .'][weight]' => $old_weight + 1);
$roles = user_roles();
$weight = count($roles);
$new_role_weights = array();
$saved_rids = array();
// Change the role weights to make the roles in reverse order.
$edit = array();
foreach ($roles as $role) {
$edit['roles['. $role->id() .'][weight]'] = $weight;
$new_role_weights[$role->id()] = $weight;
$saved_rids[] = $role->id;
$weight--;
}
$this->drupalPost('admin/people/roles', $edit, t('Save order'));
$this->assertText(t('The role settings have been updated.'), 'The role settings form submitted successfully.');
// Retrieve the saved role and compare its weight.
$role = user_role_load($rid);
$new_weight = $role->weight;
$this->assertTrue(($old_weight + 1) == $new_weight, 'Role weight updated successfully.');
// Load up the user roles with the new weights.
drupal_static_reset('user_roles');
$roles = user_roles();
$rids = array();
// Test that the role weights have been correctly saved.
foreach ($roles as $role) {
$this->assertEqual($role->weight, $new_role_weights[$role->id()]);
$rids[] = $role->id;
}
// The order of the roles should be reversed.
$this->assertIdentical($rids, array_reverse($saved_rids));
}
}
<?php
/**
* @file
* Contains Drupal\user\Tests\Views\HandlerFieldRoleTest.
*/
namespace Drupal\user\Tests\Views;
/**
* Tests the role field handler.
*
* @see views_handler_field_user_name
*/
class HandlerFieldRoleTest extends UserTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = array('test_views_handler_field_role');
public static function getInfo() {
return array(
'name' => 'User: Role Field',
'description' => 'Tests the handler of the user: role field.',
'group' => 'Views Modules',
);
}
public function testRole() {
// Create a couple of roles for the view.
$rolename_a = 'a' . $this->randomName(8);
$rid_a = $this->drupalCreateRole(array('access content'), $rolename_a, $rolename_a, 9);
$rolename_b = 'b' . $this->randomName(8);
$rid_b = $this->drupalCreateRole(array('access content'), $rolename_b, $rolename_b, 8);
$rolename_not_assigned = $this->randomName(8);
$this->drupalCreateRole(array('access content'), $rolename_not_assigned, $rolename_not_assigned);
// Add roles to user 1.
$user = user_load(1);
$user->roles[$rid_a] = $rolename_a;
$user->roles[$rid_b] = $rolename_b;
$user->save();
$view = views_get_view('test_views_handler_field_role');
$this->executeView($view);
$view->row_index = 0;
// The role field is populated during pre_render.
$view->field['rid']->pre_render($view->result);
$render = $view->field['rid']->advanced_render($view->result[0]);
$this->assertEqual($rolename_b . $rolename_a, $render, 'View test_views_handler_field_role renders role assigned to user in the correct order.');
$this->assertFalse(strpos($render, $rolename_not_assigned), 'View test_views_handler_field_role does not render a role not assigned to a user.');
}
}
......@@ -34,9 +34,9 @@ function attachLoad(&$queried_users, $load_revision = FALSE) {
}
// Add any additional roles from the database.
$result = db_query('SELECT r.rid, r.name, ur.uid FROM {role} r INNER JOIN {users_roles} ur ON ur.rid = r.rid WHERE ur.uid IN (:uids)', array(':uids' => array_keys($queried_users)));
$result = db_query('SELECT rid, uid FROM {users_roles} WHERE uid IN (:uids)', array(':uids' => array_keys($queried_users)));
foreach ($result as $record) {
$queried_users[$record->uid]->roles[$record->rid] = $record->name;
$queried_users[$record->uid]->roles[$record->rid] = $record->rid;
}
// Call the default attachLoad() method. This will add fields and call
......
api_version: '3.0'
base_field: uid
base_table: users
core: 8.x
description: ''
disabled: '0'
display:
default:
display_plugin: default
id: default
display_title: Master
position: ''
display_options:
access:
type: perm
perm: 'access user profiles'
cache:
type: none
query:
type: views_query
exposed_form:
type: basic
pager:
type: none
options:
items_per_page: ''
style:
type: default
row:
type: fields
fields:
name:
id: name
table: users
field: name
relationship: none
group_type: group
admin_label: ''
label: Name
exclude: '0'
alter:
alter_text: '0'
text: ''
make_link: '0'
path: ''
absolute: '0'
external: '0'
replace_spaces: '0'
path_case: none
trim_whitespace: '0'
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: '0'
max_length: ''
word_boundary: '1'
ellipsis: '1'
more_link: '0'
more_link_text: ''
more_link_path: ''
strip_tags: '0'
trim: '0'
preserve_tags: ''
html: '0'
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: '1'
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: '1'
empty: ''
hide_empty: '0'
empty_zero: '0'
hide_alter_empty: '1'
link_to_user: '1'
overwrite_anonymous: '0'
anonymous_text: ''
format_username: '1'
rid:
id: rid
table: users_roles
field: rid
relationship: none
group_type: group
admin_label: ''
label: Roles
exclude: '0'
alter:
alter_text: '0'
text: ''
make_link: '0'
path: ''
absolute: '0'
external: '0'
replace_spaces: '0'
path_case: none
trim_whitespace: '0'
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: '0'
max_length: ''
word_boundary: '1'
ellipsis: '1'