role_delegation.module in Role Delegation 6
Same filename and directory in other branches
This module allows site administrators to grant some roles the authority to assign selected roles to users, without them needing the 'administer access control' permission.
It provides its own tab in the user profile so that roles can be assigned without needing access to the user edit form.
File
role_delegation.moduleView source
<?php
/**
* @file
*
* This module allows site administrators to grant some roles the authority to
* assign selected roles to users, without them needing the 'administer access
* control' permission.
*
* It provides its own tab in the user profile so that roles can be assigned
* without needing access to the user edit form.
*/
/**
* Implementation of hook_help().
*/
function role_delegation_help($section) {
switch ($section) {
case 'admin/help#role_delegation':
return '<p>' . t('This module allows site administrators to grant some roles the authority to assign selected roles to users, without them needing the <em>administer permissions</em> permission.') . '</p><p>' . t('It provides its own tab in the user profile so that roles can be assigned without needing access to the user edit form.') . '</p>';
}
}
/**
* Implementation of hook_perm().
*/
function role_delegation_perm() {
$roles = _role_delegation_roles();
$perms = array(
'assign all roles',
);
foreach ($roles as $role) {
$perms[] = _role_delegation_make_perm($role);
}
return $perms;
}
/**
* Implementation of hook_menu().
*/
function role_delegation_menu() {
global $user;
$items = array();
$items['user/%user/roles'] = array(
'title' => 'Roles',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'role_delegation_roles_form',
1,
),
'access callback' => 'role_delegation_access',
'type' => MENU_LOCAL_TASK,
);
return $items;
}
/**
* Provides a form for assigning roles to the current user.
*/
function role_delegation_roles_form(&$form_state, $account) {
$form['roles'] = array(
'#type' => 'fieldset',
'#title' => t('Roles'),
'#tree' => TRUE,
);
// Provide a separate checkbox for each role but hide those the user has no authority over.
$roles = _role_delegation_roles();
$roles_preserve = array(
'authenticated user',
);
foreach ($roles as $rid => $role) {
if (!(user_access('assign all roles') || user_access(_role_delegation_make_perm($role)) || user_access('administer permissions'))) {
// Hide roles the user can't assign.
$form['roles'][$rid] = array(
'#type' => 'value',
'#value' => isset($account->roles[$rid]),
);
if (isset($account->roles[$rid])) {
$roles_preserve[] = $role;
}
}
else {
$form['roles'][$rid] = array(
'#type' => 'checkbox',
'#title' => check_plain($role),
'#default_value' => isset($account->roles[$rid]),
);
}
}
$form['roles']['#description'] = t('The user receives the combined permissions of the %roles role(s), and all roles selected here. ', array(
'%roles' => implode(', ', $roles_preserve),
));
$form['account'] = array(
'#type' => 'value',
'#value' => $account,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
);
drupal_set_title(check_plain($account->name));
return $form;
}
/**
* Saves the roles assigned to the account given in the form.
*/
function role_delegation_roles_form_submit($form, &$form_state) {
if (is_array($form_state['values']['roles']) && isset($form_state['values']['account']->uid)) {
$account = user_load(array(
'uid' => (int) $form_state['values']['account']->uid,
));
$myroles = array();
$rolenames = user_roles(TRUE);
foreach (array_keys(array_filter($form_state['values']['roles'])) as $rid) {
$myroles[$rid] = $rolenames[$rid];
}
user_save($account, array(
'roles' => $myroles,
));
// Delete the user's menu cache.
cache_clear_all($form_state['values']['account']->uid . ':', 'cache_menu', TRUE);
drupal_set_message(t('The roles have been updated.'));
}
}
/**
* Access callback for menu hook.
*/
function role_delegation_access() {
// Check access to user profile page.
if (!user_access('access user profiles')) {
return FALSE;
}
// Check if they can edit users. In that case, the Roles tab is not needed.
if (user_access('administer users')) {
return FALSE;
}
// Check access to role assignment page.
if (user_access('administer permissions')) {
return TRUE;
}
$perms = role_delegation_perm();
foreach ($perms as $perm) {
if (user_access($perm)) {
return TRUE;
}
}
return FALSE;
}
/**
* Returns all existing roles, except anonymous and authenticated user.
*/
function _role_delegation_roles() {
$roles = user_roles(TRUE);
unset($roles[DRUPAL_AUTHENTICATED_RID]);
return $roles;
}
/**
* Returns the delegation permission for a role.
*/
function _role_delegation_make_perm($role) {
return "assign {$role} role";
}
/**
* Implementation of hook_form_FORM_ID_alter() for user_admin_role().
*/
function role_delegation_form_user_admin_role_alter(&$form, $form_state) {
$form['#submit'][] = 'role_delegation_form_user_admin_role_submit';
}
/**
* Submit function for the user_admin_role form:
* When a role is renamed or deleted, rename or delete the permission
* to assign that role.
*/
function role_delegation_form_user_admin_role_submit($form, $form_state) {
$op = $form_state['values']['op'];
if ($op != t('Save role') && $op != t('Delete role')) {
return;
}
$oldrole = $form['name']['#default_value'];
$newrole = $form_state['values']['name'];
if ($op == t('Save role') && $oldrole == $newrole) {
return;
}
// Role is being renamed or deleted.
// Loop through permission lists for all roles, renaming or deleting the
// 'assign' permission for this role.
$oldperm = _role_delegation_make_perm($oldrole);
$result = db_query('SELECT * FROM {permission}');
while ($row = db_fetch_object($result)) {
$perms = explode(', ', $row->perm);
for ($i = 0; $i < count($perms); ++$i) {
if ($perms[$i] == $oldperm) {
switch ($op) {
case t('Save role'):
$perms[$i] = _role_delegation_make_perm($newrole);
break;
case t('Delete role'):
unset($perms[$i]);
break;
}
if (count($perms)) {
db_query("UPDATE {permission} SET perm = '%s' WHERE pid = %d", implode(', ', $perms), $row->pid);
}
else {
db_query("DELETE FROM {permission} WHERE pid = %d", $row->pid);
}
break;
}
}
}
}
/**
* Implementation of hook_user().
*/
function role_delegation_user($op, &$edit, &$account, $category = NULL) {
if ($op == 'register' || $op == 'form' && $category == 'account') {
// Only alter user form when user can't assign permissions without Role Delegation.
if (!user_access('administer permissions')) {
// Split up roles based on whether they can be delegated or not.
$current_roles = isset($account->roles) ? $account->roles : array();
$rids_default = array();
$rids_preserve = array(
DRUPAL_AUTHENTICATED_RID => DRUPAL_AUTHENTICATED_RID,
);
$roles_preserve = array(
'authenticated user',
);
$roles_options = array();
$roles = _role_delegation_roles();
foreach ($roles as $rid => $role) {
if (user_access('assign all roles') || user_access(_role_delegation_make_perm($role))) {
if (array_key_exists($rid, $current_roles)) {
$rids_default[] = $rid;
}
$roles_options[$rid] = $role;
}
else {
if (array_key_exists($rid, $current_roles)) {
$rids_preserve[$rid] = $rid;
$roles_preserve[] = $role;
}
}
}
if (empty($roles_options)) {
// No role can be assigned.
return;
}
// Generate the form items.
$form['roles_preserve'] = array(
'#type' => 'value',
'#value' => $rids_preserve,
);
$roles_assign = array(
'#type' => 'checkboxes',
'#title' => t('Roles'),
'#description' => t('The user receives the combined permissions of the %roles role(s), and all roles selected here. ', array(
'%roles' => implode(', ', $roles_preserve),
)),
'#options' => $roles_options,
'#default_value' => $rids_default,
'#weight' => 10,
);
if ($op == 'register') {
// Since the user module does array_merge() instead of array_merge_recursive() (see bug http://drupal.org/node/227690),
// we must move this under 'account' later at role_delegation_form_user_register_alter()
$form['roles_assign'] = $roles_assign;
}
else {
$form['account']['roles_assign'] = $roles_assign;
}
return $form;
}
}
elseif (isset($edit['roles_assign']) && ($op == 'insert' || $op == 'submit')) {
$edit['roles'] = $edit['roles_preserve'] + array_filter($edit['roles_assign']);
}
}
/**
* Implementation of hook_form_FORM_ID_alter() for user_register().
*/
function role_delegation_form_user_register_alter(&$form, $form_state) {
// Move our field where it belongs
if (isset($form['roles_assign'])) {
$form['account']['roles_assign'] = $form['roles_assign'];
unset($form['roles_assign']);
$form['account']['notify']['#weight'] = 11;
}
}
/**
* Implementation of hook_user_operations().
*/
function role_delegation_user_operations($form_state = array()) {
// Only provide role add/remove operations when user can't assign permissions
// without Role Delegation.
if (user_access('administer permissions')) {
return;
}
// Provide add/remove operations for delegated roles.
$roles = _role_delegation_roles();
$add_roles = array();
$remove_roles = array();
foreach ($roles as $rid => $role) {
if (user_access('assign all roles') || user_access(_role_delegation_make_perm($role))) {
// Use different operation names than those from user_user_operations(),
// to keep user_user_operations() from emitting a warning about the
// permissions.
$add_roles['role_delegation_add_role-' . $rid] = $role;
$remove_roles['role_delegation_remove_role-' . $rid] = $role;
}
}
if (!count($add_roles)) {
return;
}
$operations = array(
t('Add a role to the selected users') => array(
'label' => $add_roles,
),
t('Remove a role from the selected users') => array(
'label' => $remove_roles,
),
);
// If the form has been posted, insert the proper data for role editing if necessary.
if (!empty($form_state['submitted'])) {
$operation_rid = explode('-', $form_state['values']['operation']);
$operation = $operation_rid[0];
if ($operation == 'role_delegation_add_role' || $operation == 'role_delegation_remove_role') {
$rid = $operation_rid[1];
if ($add_roles['role_delegation_add_role-' . $rid]) {
$operations[$form_state['values']['operation']] = array(
'callback' => 'user_multiple_role_edit',
'callback arguments' => array(
str_replace('role_delegation_', '', $operation),
$rid,
),
);
}
else {
watchdog('security', 'Detected malicious attempt to alter protected user fields.', array(), WATCHDOG_WARNING);
return;
}
}
}
return $operations;
}
Functions
Name | Description |
---|---|
role_delegation_access | Access callback for menu hook. |
role_delegation_form_user_admin_role_alter | Implementation of hook_form_FORM_ID_alter() for user_admin_role(). |
role_delegation_form_user_admin_role_submit | Submit function for the user_admin_role form: When a role is renamed or deleted, rename or delete the permission to assign that role. |
role_delegation_form_user_register_alter | Implementation of hook_form_FORM_ID_alter() for user_register(). |
role_delegation_help | Implementation of hook_help(). |
role_delegation_menu | Implementation of hook_menu(). |
role_delegation_perm | Implementation of hook_perm(). |
role_delegation_roles_form | Provides a form for assigning roles to the current user. |
role_delegation_roles_form_submit | Saves the roles assigned to the account given in the form. |
role_delegation_user | Implementation of hook_user(). |
role_delegation_user_operations | Implementation of hook_user_operations(). |
_role_delegation_make_perm | Returns the delegation permission for a role. |
_role_delegation_roles | Returns all existing roles, except anonymous and authenticated user. |