You are here

role_delegation.module in Role Delegation 5

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.module
View 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 access control</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($may_cache) {
  global $user;
  $items = array();
  if (!$may_cache) {
    if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
      $account = user_load(array(
        'uid' => arg(1),
      ));

      // Determine access to user profile page (same as user.module).
      $profile_access = $user->uid == arg(1) || user_access('access user profiles');
      $profile_access &= $account->status || user_access('administer users');

      // Determine access to role assignment page.
      $delegation_access = FALSE;
      if (!user_access('administer users') && !($delegation_access = user_access('administer access control'))) {
        $perms = role_delegation_perm();
        foreach ($perms as $perm) {
          if (user_access($perm)) {
            $delegation_access = TRUE;
            break;
          }
        }
      }
      $items[] = array(
        'path' => 'user/' . arg(1) . '/roles',
        'title' => t('Roles'),
        'callback' => 'drupal_get_form',
        'callback arguments' => array(
          'role_delegation_roles_form',
          $account,
        ),
        'access' => $profile_access && $delegation_access,
        'type' => MENU_LOCAL_TASK,
      );
    }
  }
  return $items;
}

/**
 * Provides a form for assigning roles to the current user.
 */
function role_delegation_roles_form($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 access control'))) {

      // 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_id, $form_values) {
  if (is_array($form_values['roles']) && isset($form_values['account']->uid)) {
    $account = user_load(array(
      'uid' => (int) $form_values['account']->uid,
    ));
    $myroles = array();
    $rolenames = user_roles(TRUE);
    foreach (array_keys(array_filter($form_values['roles'])) as $rid) {
      $myroles[$rid] = $rolenames[$rid];

      // we don't need to have the role name
    }
    user_save($account, array(
      'roles' => $myroles,
    ));

    // Delete the user's menu cache.
    cache_clear_all($form_values['account']->uid . ':', 'cache_menu', TRUE);
    drupal_set_message(t('The roles have been updated.'));
  }
}

/**
 * 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. Any characters from the role
 * that are not allowed in permission names are filtered out.
 */
function _role_delegation_make_perm($role) {

  // Allow alphanumerics, space, hyphen, underscore.
  $role = preg_replace('/[^a-zA-Z0-9 \\-_]/', '', $role);
  return "assign {$role} role";
}

/**
 * Implementation of hook_form_alter().
 */
function role_delegation_form_alter($form_id, &$form) {

  // Only alter user form when user can't assign permissions without Role Delegation.
  if ($form_id != 'user_register' && $form_id != 'user_edit') {
    return;
  }
  if (user_access('administer access control')) {
    return;
  }

  // Split up roles based on whether they can be delegated or not.
  $current_roles = is_numeric(arg(1)) && ($user = user_load(array(
    'uid' => arg(1),
  ))) ? $user->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,
  );
  $assign_item = 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,
  );
  if (isset($form['account'])) {
    $form['account']['roles_assign'] = $assign_item;
  }
  else {
    $form['roles_assign'] = $assign_item;
  }
}

/**
 * Implementation of hook_user().
 */
function role_delegation_user($op, &$edit, &$account, $category = NULL) {
  if ($op != 'insert' && $op != 'submit') {
    return;
  }
  if (!isset($edit['roles_assign'])) {
    return;
  }
  $edit['roles'] = $edit['roles_preserve'] + array_filter($edit['roles_assign']);
}

Functions

Namesort descending Description
role_delegation_form_alter Implementation of hook_form_alter().
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_make_perm Returns the delegation permission for a role. Any characters from the role that are not allowed in permission names are filtered out.
_role_delegation_roles Returns all existing roles, except anonymous and authenticated user.