This repository has been archived on 2025-06-21. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
suitedesk/modules/role_delegation/role_delegation.module

343 lines
11 KiB
Text

<?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)
{
// Put our submit function in line ahead of user_admin_role_submit(),
// so that it can make use of the old role name before it's changed to the new.
array_unshift($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;
}
$rid = $form_state['values']['rid'];
$oldrole = db_result(db_query('SELECT name FROM {role} WHERE rid = %d', $rid));
$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;
}