Created
October 6, 2011 15:15
-
-
Save arturo-c/1267652 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @file | |
* Allows users of a particular role to create sub user account in another role. | |
* | |
* Copyright 2008-2009 by Jimmy Berry ("boombatower", http://drupal.org/user/214218) | |
*/ | |
/* | |
* Variables loaded as constants. | |
*/ | |
define('SUBUSER_PARENT', variable_get('subuser_parent', 'Parent')); | |
define('SUBUSER_LIST', variable_get('subuser_list', 'Subusers')); | |
define('SUBUSER_CREATE', variable_get('subuser_create', 'Create subuser')); | |
define('SUBUSER_ADMINISTER', variable_get('subuser_administer', 'Administer subusers')); | |
/** | |
* Implementation of hook_menu(). | |
*/ | |
function subuser_menu() { | |
$items = array(); | |
$items['admin/settings/subuser'] = array( | |
'title' => 'Subuser', | |
'description' => 'Define what, if any, roles are assigned to a new subuser.', | |
'page callback' => 'drupal_get_form', | |
'page arguments' => array('subuser_settings_form'), | |
'access arguments' => array('administer subuser settings'), | |
'file' => 'subuser.pages.inc' | |
); | |
$items['user/%user/subuser/create'] = array( | |
'title' => variable_get('subuser_create', 'Create subuser'), | |
'page callback' => 'drupal_get_form', | |
'page arguments' => array('subuser_create_form', 1), | |
'access callback' => 'subuser_user_create_access', | |
'access arguments' => array(1), | |
'type' => MENU_CALLBACK, | |
'file' => 'subuser.pages.inc' | |
); | |
$items['subuser/switch/%'] = array( | |
'title' => 'Switch subuser', | |
'page callback' => 'subuser_switch_user', | |
'page arguments' => array(2), | |
'access callback' => 'subuser_switch_user_access', | |
'access arguments' => array(2), | |
'type' => MENU_CALLBACK, | |
); | |
return $items; | |
} | |
/** | |
* Implementation of hook_perm(). | |
*/ | |
function subuser_perm() { | |
return array( | |
'create subuser', | |
'switch subuser', | |
'administer subuser settings', | |
'administer subusers', | |
'bypass subuser limit', | |
); | |
} | |
/** | |
* Implementation of hook_menu_link_alter(). | |
* | |
* Allow the logout link to be altered. | |
* | |
* @see, subuser_translated_menu_link_alter() | |
*/ | |
function subuser_menu_link_alter(&$item, $menu) { | |
if ($item['link_path'] == 'logout') { | |
$item['options']['alter'] = TRUE; | |
} | |
} | |
/** | |
* Implementation of hook_translated_menu_link_alter(). | |
* | |
* If currently running as a child user change the "Log out" link to | |
* "Log out (return)". | |
*/ | |
function subuser_translated_menu_link_alter(&$item, $map) { | |
if ($item['href'] == 'logout' && isset($_SESSION['subuser_uid'])) { | |
$item['title'] = t('Log out (return)'); | |
$item['href'] = 'subuser/switch/' . $_SESSION['subuser_uid']; | |
} | |
} | |
/** | |
* Implementation of hook_menu_link_alter(). | |
*/ | |
function subuser_menu_alter(&$items) { | |
$items['user/%user_category/edit']['access callback'] = 'subuser_user_edit_access'; | |
$items['admin/user/user']['access callback'] = 'subuser_administer_users_access'; | |
$items['admin/user/user']['title callback'] = 'subuser_administer_users_title'; | |
} | |
/** | |
* Modified version of user_edit_access() for 'administer subusers' logic. | |
*/ | |
function subuser_user_edit_access($account) { | |
// Condition from user_edit_access(). | |
if ((($GLOBALS['user']->uid == $account->uid) || user_access('administer users')) && $account->uid > 0) { | |
return TRUE; | |
} | |
// Check if user can administer subusers and the user being editted is a | |
// subuser of the active user. | |
if (user_access('administer subusers') && | |
db_result(db_query('SELECT uid FROM {subuser_relationship} WHERE uid = %d AND parent_id = %d', $account->uid, $GLOBALS['user']->uid))) { | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/** | |
* Access callback for user/%user/subuser/create. | |
* | |
* If user has 'administer users' or 'administer subusers' or if they have | |
* 'create subser' and they are adding a subuser to their own account then | |
* allow access. | |
* | |
* @param $account | |
* User object representing the account which subusers will be added to. | |
* | |
* @return | |
* TRUE if access is granted otherwise FALSE. | |
*/ | |
function subuser_user_create_access($account) { | |
global $user; | |
if (user_access('administer users') || ((user_access('create subuser') || user_access('administer subusers')) && $account->uid == $user->uid)) { | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/** | |
* Access callback for admin/user/user page. | |
* | |
* If user has 'administer users' or 'administer subusers' then allow them to | |
* view the administer users page. Filter the view to only the user's they are | |
* a parent of if they do not have the 'administer users' permission. | |
* | |
* @return boolean TRUE access granted, otherwise FALSE. | |
*/ | |
function subuser_administer_users_access() { | |
if (user_access('administer users')) { | |
return TRUE; | |
} | |
if (user_access('administer subusers')) { | |
global $user; | |
if (!isset($_SESSION['user_overview_filter'])) { | |
$_SESSION['user_overview_filter'] = array(); | |
} | |
// Look for the subuser filter and ensure it is set to the current user if | |
// found, otherwise it will be added bellow. | |
$found = FALSE; | |
foreach ($_SESSION['user_overview_filter'] as $index => $filter) { | |
list($key, $value) = $filter; | |
if ($key == 'subuser') { | |
$_SESSION['user_overview_filter'][$index][1] = $user->uid; | |
$found = TRUE; | |
break; | |
} | |
} | |
// Explicitly add the filter. | |
if (!$found) { | |
$_SESSION['user_overview_filter'][] = array( | |
'subuser', | |
$user->uid, | |
); | |
} | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/** | |
* Title callback for admin/user/user page. | |
* | |
* Set the title to the custom subuser administer title when user has | |
* 'administer subusers' and not 'administer users' permission. | |
* | |
* @return string Either default title or custom subuser title. | |
*/ | |
function subuser_administer_users_title() { | |
if (!user_access('administer users') && user_access('administer subusers')) { | |
return t(SUBUSER_ADMINISTER); | |
} | |
return t('Users'); | |
} | |
/** | |
* Check if the user has permission to switch the specified user. | |
* | |
* Pass cases: | |
* - Super user. | |
* - Returning to parent account. | |
* - The user is a parent of the user being switched to. | |
* | |
* @param integer $uid User ID being switched to. | |
* @return boolean Access granted. | |
*/ | |
function subuser_switch_user_access($uid) { | |
global $user; | |
if ($user->uid == 1 || (user_access('switch subuser') && | |
((isset($_SESSION['subuser_uid']) && $uid == $_SESSION['subuser_uid']) || | |
db_result(db_query('SELECT uid FROM {subuser_relationship} WHERE uid = %d AND parent_id = %d', $uid, $user->uid))))) { | |
return TRUE; | |
} | |
return FALSE; | |
} | |
/** | |
* Switch from a parent user to a subuser (or child user). | |
* | |
* @param $uid The user id to switch to. | |
*/ | |
function subuser_switch_user($uid) { | |
global $user; | |
if ($uid) { | |
$_SESSION['subuser_uid'] = ((isset($_SESSION['subuser_uid']) && $uid == $_SESSION['subuser_uid']) ? NULL : $user->uid); | |
$user = user_load($uid); | |
} | |
drupal_goto('user/' . $uid); | |
} | |
/** | |
* Implementation of hook_user(). | |
*/ | |
function subuser_user($op, &$edit, &$account, $category = NULL) { | |
global $user; | |
switch ($op) { | |
case 'form': | |
// Allow users with sufficient permission to limit the number of subusers on a per-user basis. | |
if (user_access('administer subuser settings')) { | |
$user_limit = db_result(db_query("SELECT subuser_limit FROM {subuser_limit} WHERE uid=%d", $account->uid)); | |
$form['subuser_limit'] = array( | |
'#type' => 'textfield', | |
'#title' => t('Subuser limit'), | |
'#description' => t('Enter the maximum number of subusers this user can create'), | |
'#default_value' => ($user_limit) ? $user_limit : variable_get('subuser_limit', NULL), | |
'#size' => 5, | |
'#maxlength' => 4, | |
); | |
return $form; | |
} | |
break; | |
case 'insert': | |
if (isset($edit['origin']) && $edit['origin'] == 'subuser') { | |
db_query('INSERT INTO {subuser_relationship} (parent_id, uid) | |
VALUES (%d, %d)', $edit['parent_user'], $account->uid); | |
} | |
break; | |
case 'update': | |
// Check and see if we even need to bother ourselves with subusers at all. | |
$subusers = subuser_get_subusers($account->uid); | |
if (count($subusers) > 0) { | |
// If we're blocking a user, get the subusers so we can block them too. | |
$block_subusers = variable_get('subuser_children_block', NULL); | |
if ($account->status == 1 && $block_subusers == 1 && isset($edit['status']) && $edit['status'] == 0) { | |
subuser_block_subusers($subusers); | |
} | |
// If we're unblocking a user, get the subusers so we can unblock them too. | |
$unblock_subusers = variable_get('subuser_children_unblock', NULL); | |
if ($account->status == 0 && $unblock_subusers == 1 && isset($edit['status']) && $edit['status'] == 1) { | |
subuser_unblock_subusers($subusers); | |
} | |
} | |
// Allow role changes to cascade down to subusers. | |
$role_change_subusers = variable_get('subuser_children_roles', NULL); | |
if ($role_change_subusers == 1) { | |
$new_roles = $edit['roles']; | |
$old_roles = $account->roles; | |
// Compare the count of old and new roles, > 1 means roles added, < 0 means they've been removed. | |
$role_change = count($new_roles) - count($old_roles); | |
if ($role_change !== 0) { | |
if (is_array($new_roles) && is_array($old_roles)) { | |
// Are we exempting a role from cascading? If so pull it out of new & old roles. | |
$rid = variable_get('subuser_cascade_exempt_rid', NULL); | |
if (isset($rid)) { | |
unset($old_roles[$rid]); | |
unset($new_roles[$rid]); | |
} | |
$old_keys = array_keys($old_roles); | |
$new_keys = array_keys($new_roles); | |
// We need to do the diff backwards depending on if we have a role addition or subtraction. | |
$diff = ($role_change > 0) ? array_diff($new_keys, $old_keys) : array_diff($old_keys, $new_keys); | |
$op = ($role_change > 0) ? 'add_role' : 'remove_role'; | |
subuser_tweak_roles_of_subusers($subusers, $op, $diff); | |
} | |
} | |
} | |
// Check to see if this user has a subuser limit set (and it's not the default value). | |
if (isset($edit['subuser_limit']) && $edit['subuser_limit'] !== variable_get('subuser_limit', NULL)) { | |
db_query("INSERT INTO {subuser_limit} (uid, subuser_limit) VALUES (%d, %d) ON DUPLICATE KEY UPDATE subuser_limit = %d", $account->uid, $edit['subuser_limit'], $edit['subuser_limit']); | |
unset($edit['subuser_limit']); | |
} | |
break; | |
case 'delete': | |
$subusers = subuser_get_subusers($account->uid); | |
// If there are subusers for this account, figure out what to do with them. | |
if (count($subusers) > 0) { | |
$subuser_orphaned_children = variable_get('subuser_orphaned_children', 0); | |
if ($subuser_orphaned_children == 1) { | |
// Block the subuser accounts too. | |
subuser_block_subusers($subusers); | |
} | |
if ($subuser_orphaned_children == 2) { | |
// Delete the subuser accounts too. | |
foreach ($subusers as $uid) { | |
user_delete(NULL, $uid); | |
} | |
} | |
} | |
db_query('DELETE FROM {subuser_relationship} WHERE uid = %d', $account->uid); | |
break; | |
case 'view': | |
$parent = db_fetch_object(db_query('SELECT parent_id | |
FROM {subuser_relationship} | |
WHERE uid = %d', $account->uid)); | |
if ($parent) { | |
// Display link to parent user if available. | |
$parent = user_load($parent->parent_id); | |
$account->content['subuser_parent'] = array( | |
'#type' => 'user_profile_item', | |
'#title' => t(SUBUSER_PARENT), | |
'#value' => theme('username', $parent), | |
'#weight' => 10, | |
); | |
} | |
// The parent user should either have access to create subusers, or have | |
// existing subusers. | |
$create = subuser_user_create_access($account); | |
// Check for a per-user limit on the number of subusers that this user can create. | |
$limit = subuser_get_subuser_limit($account->uid); | |
$current_subuser_count = count(subuser_get_subusers($account->uid)); | |
$over_limit = ($limit - $current_subuser_count > 0) ? FALSE : TRUE; | |
$administer = user_access('administer users') || (user_access('administer subusers') && $account->uid == $user->uid); | |
$show_administer_link = variable_get('subuser_show_admin', 1); | |
$view = views_get_view('subusers'); | |
if ($create || (isset($view->results) && $view->results)) { | |
$view = views_embed_view('subusers'); | |
if ($create && (!$over_limit || user_access('bypass subuser limit'))) { | |
$links[] = l(t(SUBUSER_CREATE), 'user/' . $account->uid . '/subuser/create'); | |
} | |
if ($administer && $current_subuser_count >= 1 && $show_administer_link) { | |
$links[] = l(t(SUBUSER_ADMINISTER), 'admin/user/user'); | |
} | |
if (isset($links)) { | |
$output = implode(' | ', $links); | |
} | |
$output .= '<br />' . $view; | |
$account->content['subuser'] = array( | |
'#type' => 'user_profile_category', | |
'#title' => t(SUBUSER_LIST), | |
'#weight' => 11, | |
); | |
$account->content['subuser']['list'] = array( | |
'#type' => 'user_profile_item', | |
'#value' => $output, | |
'#weight' => 11, | |
); | |
} | |
break; | |
} | |
} | |
/** | |
* API function to get the subuser accounts of a specified parent account. | |
* | |
* @param $uid | |
* [optional] The uid of a potential parent account. Defaults to current user. | |
* @return | |
* Array of subuser uids. | |
*/ | |
function subuser_get_subusers($uid = NULL) { | |
if ($uid == NULL) { | |
$uid = $GLOBALS['user']->uid; | |
} | |
$users = array(); | |
$results = db_query("SELECT uid FROM {subuser_relationship} WHERE parent_id = %d", $uid); | |
while ($u = db_fetch_array($results)) { | |
$users[$u['uid']] = $u['uid']; | |
} | |
return $users; | |
} | |
/** | |
* API function to identify any parent for a given user account. | |
* | |
* @param $uid | |
* [optional] The uid of a potential subuser account. Defaults to current user. | |
* @return | |
* The parent uid or FALSE. | |
*/ | |
function subuser_get_parent($uid = NULL) { | |
if ($uid == NULL) { | |
$uid = $GLOBALS['user']->uid; | |
} | |
return db_result(db_query("SELECT parent_id FROM {subuser_relationship} WHERE uid = %d", $uid)); | |
} | |
/** | |
* API function to get the max number of subusers this user is allowed to create. | |
* | |
* @param $uid | |
* [optional] The uid of the parent account. Defaults to the global site-wide limit. | |
* @return | |
* Integer limit | |
*/ | |
function subuser_get_subuser_limit($uid = NULL) { | |
// Check to see if this user has a specific limit. | |
if ($uid !== NULL) { | |
$limit = (int) db_result(db_query("SELECT subuser_limit FROM {subuser_limit} WHERE uid = %d", $uid)); | |
} | |
// If we don't have a limit for this user, or we don't have a uid use the global limit. | |
if ($uid == NULL || $limit == NULL) { | |
$limit = (int) variable_get('subuser_limit', NULL); | |
} | |
return $limit; | |
} | |
/** | |
* Function to block subusers when a parent is blocked. | |
* | |
* @param $uid | |
* [optional] The array of subusers, from subuser_get_subusers(), we're interested in blocking. | |
*/ | |
function subuser_block_subusers($subusers = NULL) { | |
if ($subusers == NULL) { | |
global $user; | |
$subusers = subuser_get_subusers($user->uid); | |
} | |
foreach ($subusers as $uid) { | |
$account = user_load(array('uid' => (int)$uid)); | |
// Skip blocking user if they are already blocked. | |
if ($account !== FALSE && $account->status == 1) { | |
user_save($account, array('status' => 0)); | |
} | |
} | |
} | |
/** | |
* Function to unblock subusers when a parent is unblocked. | |
* | |
* @param $subusers | |
* [optional] The array of subusers, from subuser_get_subusers(), we're interested in un-blocking. | |
*/ | |
function subuser_unblock_subusers($subusers = NULL) { | |
if ($subusers == NULL) { | |
global $user; | |
$subusers = subuser_get_subusers($user->uid); | |
} | |
foreach ($subusers as $uid) { | |
$account = user_load(array('uid' => (int)$uid)); | |
// Skip unblocking user if they are already unblocked. | |
if ($account !== FALSE && $account->status == 0) { | |
user_save($account, array('status' => 1)); | |
} | |
} | |
} | |
/** | |
* Function to add roles to subusers based on the parent's account change. | |
* | |
* @param $subusers | |
* An array of user id's (key & value uid) as returned by subuser_get_subusers. | |
* @param $op | |
* Either 'add_role' or 'remove_role' as required by user_multiple_role_edit(). | |
* @param $diff | |
* An array of role id's to add or remove from each of the subusers. | |
*/ | |
function subuser_tweak_roles_of_subusers($subusers, $op, $diff) { | |
if (is_array($diff) && is_array($subusers)) { | |
foreach ($diff as $rid) { | |
user_multiple_role_edit($subusers, $op, $rid); | |
} | |
} | |
} | |
/** | |
* Implementation of hook_views_api(). | |
*/ | |
function subuser_views_api() { | |
return array( | |
'api' => 2, | |
); | |
} | |
/** | |
* Implementation of hook_views_data(). | |
*/ | |
function subuser_views_data() { | |
$data['subuser_relationship']['table']['group'] = t('Subuser Relationship'); | |
$data['subuser_relationship']['table']['join']['users'] = array( | |
'left_field' => 'uid', | |
'field' => 'uid', | |
); | |
$data['subuser_relationship']['rid'] = array( | |
'title' => t('Relationship: ID'), | |
'help' => t('The relationship id'), | |
); | |
$data['subuser_relationship']['uid'] = array( | |
'title' => t('Uid'), | |
'help' => t('The ID of the Sub User.'), | |
'field' => array( | |
'handler' => 'views_handler_field_user', | |
'click sortable' => TRUE, | |
), | |
'argument' => array( | |
'handler' => 'views_handler_argument_user_uid', | |
'name field' => 'title', | |
'numeric' => TRUE, | |
'validate type' => 'uid', | |
), | |
'filter' => array( | |
'handler' => 'views_handler_filter_numeric', | |
), | |
'sort' => array( | |
'handler' => 'views_handler_sort', | |
), | |
); | |
$data['subuser_relationship']['parent_id'] = array( | |
'title' => t('Parent Id'), | |
'help' => t('The ID of the Parent User.'), | |
'field' => array( | |
'handler' => 'views_handler_field_user', | |
'click sortable' => TRUE, | |
), | |
'argument' => array( | |
'handler' => 'views_handler_argument_user_uid', | |
'name field' => 'title', | |
'numeric' => TRUE, | |
'validate type' => 'uid', | |
), | |
'relationship' => array( | |
'base' => 'users', | |
'field' => 'uid', | |
'handler' => 'views_handler_relationship', | |
'label' => t('Parent'), | |
), | |
'filter' => array( | |
'handler' => 'views_handler_filter_numeric', | |
), | |
'sort' => array( | |
'handler' => 'views_handler_sort', | |
), | |
); | |
// Provide an alternative edit link that respects administer subusers | |
// permissions and uses subuser_user_edit_access() to verify the current user | |
// can access the account in question. | |
$data['users']['edit_subuser']= array( | |
'field' => array( | |
'title' => t('Edit subuser link'), | |
'help' => t('Provide a simple link to edit the subuser. Respects administer subusers permission.'), | |
'handler' => 'subuser_handler_field_user_link_edit', | |
), | |
); | |
// Provide a link for switching to a subuser account that respects switch | |
// subusers permissions and uses subuser_switch_user_access() to verify the | |
// current user can switch to the account in question. | |
$data['users']['switch_subuser']= array( | |
'field' => array( | |
'title' => t('Switch to subuser link'), | |
'help' => t('Provide a simple link to switch to the subuser.'), | |
'handler' => 'subuser_handler_field_user_link_switch', | |
), | |
); | |
return $data; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment