At the same time, I took the opportunity to try to work on some of the usability issues on this page. Note that I have not quite finished! So don't comment until tomorrow.
In the course of doing this, I also did: half of
MDL-11529 Show the number of assignees of each role in the change role dropdown on this page.
MDL-17067 Make it clear in the UI that admins are not allowed to unassign themselves.
+++ /dev/null
-<form id="assignform" method="post" action="">
-<div style="text-align:center;">
-<label for="extendperiod"><?php print_string('enrolperiod') ?></label> <?php choose_from_menu($periodmenu, "extendperiod", $defaultperiod, $unlimitedperiod); ?>
-<label for="extendbase"><?php print_string('startingfrom') ?></label> <?php choose_from_menu($basemenu, "extendbase", 3, ""); ?>
-
-<input type="hidden" name="userid" value="<?php p($userid) ?>" />
-<input type="hidden" name="courseid" value="<?php p($courseid) ?>" />
-<input type="hidden" name="sesskey" value="<?php p(sesskey()) ?>" />
-<input type="hidden" name="contextid" value="<?php p($contextid) ?>" />
-<input type="hidden" name="roleid" value="<?php p($roleid) ?>" />
- <table summary="" style="margin-left:auto;margin-right:auto" border="0" cellpadding="5" cellspacing="0">
- <tr>
- <td valign="top">
- <label for="removeselect"><?php print_string('existingusers', 'role', count($contextusers)); ?></label>
- <br />
- <select name="removeselect[]" size="20" id="removeselect" multiple="multiple"
- onfocus="getElementById('assignform').add.disabled=true;
- getElementById('assignform').remove.disabled=false;
- getElementById('assignform').addselect.selectedIndex=-1;">
-
- <?php
- $i = 0;
- foreach ($contextusers as $contextuser) {
- $fullname = fullname($contextuser, true);
- if ($contextuser->hidden) {
- $hidden=' ('.get_string('hiddenassign').') ';
- } else {
- $hidden="";
- }
- echo "<option value=\"$contextuser->id\">".$fullname.", ".$contextuser->email.$hidden."</option>\n";
- $i++;
- }
- if ($i==0) {
- echo '<option/>'; // empty select breaks xhtml strict
- }
- ?>
-
- </select></td>
- <td valign="top">
- <br />
- <label title="<?php print_string('hiddenassign') ?>">
- <input type="checkbox" name="hidden" value="1" />
- <img src="<?php echo $CFG->pixpath; ?>/t/hide.gif" alt="<?php print_string('hiddenassign') ?>" class="hide-show-image" />
- <?php helpbutton('hiddenassign', get_string('hiddenassign')); ?>
- </label>
- <?php check_theme_arrows(); ?>
- <p class="arrow_button">
- <input name="add" id="add" type="submit" value="<?php echo $THEME->larrow.' '.get_string('add'); ?>" title="<?php print_string('add'); ?>" /><br />
- <input name="remove" id="remove" type="submit" value="<?php echo get_string('remove').' '.$THEME->rarrow; ?>" title="<?php print_string('remove'); ?>" />
- </p>
- </td>
- <td valign="top">
- <label for="addselect"><?php print_string('potentialusers', 'role', $usercount); ?></label>
- <br />
- <select name="addselect[]" size="20" id="addselect" multiple="multiple"
- onfocus="getElementById('assignform').add.disabled=false;
- getElementById('assignform').remove.disabled=true;
- getElementById('assignform').removeselect.selectedIndex=-1;">
- <?php
- $i=0;
- if (!empty($searchtext)) {
- echo "<optgroup label=\"$strsearchresults (" . $usercount . ")\">\n";
- foreach ($availableusers as $user) {
- $fullname = fullname($user, true);
- echo "<option value=\"$user->id\">".$fullname.", ".$user->email."</option>\n";
- $i++;
- }
- echo "</optgroup>\n";
-
- } else {
- if ($usercount > MAX_USERS_PER_PAGE) {
- echo '<optgroup label="'.get_string('toomanytoshow').'"><option></option></optgroup>'."\n"
- .'<optgroup label="'.get_string('trysearching').'"><option></option></optgroup>'."\n";
- } else {
- foreach ($availableusers as $user) {
- $fullname = fullname($user, true);
- echo "<option value=\"$user->id\">".$fullname.", ".$user->email."</option>\n";
- $i++;
- }
- }
- }
- if ($i==0) {
- echo '<option/>'; // empty select breaks xhtml strict
- }
- ?>
- </select>
- <br />
- <label for="searchtext" class="accesshide"><?php p($strsearch) ?></label>
- <input type="text" name="searchtext" id="searchtext" size="30" value="<?php p($searchtext, true) ?>"
- onfocus ="getElementById('assignform').add.disabled=true;
- getElementById('assignform').remove.disabled=true;
- getElementById('assignform').removeselect.selectedIndex=-1;
- getElementById('assignform').addselect.selectedIndex=-1;"
- onkeydown = "var keyCode = event.which ? event.which : event.keyCode;
- if (keyCode == 13) {
- getElementById('assignform').previoussearch.value=1;
- getElementById('assignform').submit();
- } " />
- <input name="search" id="search" type="submit" value="<?php p($strsearch) ?>" />
- <?php
- if (!empty($searchtext)) {
- echo '<input name="showall" id="showall" type="submit" value="'.$strshowall.'" />'."\n";
- }
- ?>
- </td>
- </tr>
- </table>
-</div>
-</form>
-
-
<?php // $Id$
// Script to assign users to contexts
- require_once('../../config.php');
- require_once($CFG->dirroot.'/mod/forum/lib.php');
+ require_once(dirname(__FILE__) . '/../../config.php');
require_once($CFG->libdir.'/adminlib.php');
+ require_once($CFG->dirroot.'/user/selector/lib.php');
+ require_js(array('yui_yahoo', 'yui_dom', 'yui_event'));
+ require_js($CFG->admin . '/roles/roles.js');
- define("MAX_USERS_PER_PAGE", 5000);
define("MAX_USERS_TO_LIST_PER_ROLE", 10);
- $contextid = required_param('contextid',PARAM_INT); // context id
- $roleid = optional_param('roleid', 0, PARAM_INT); // required role id
- $add = optional_param('add', 0, PARAM_BOOL);
- $remove = optional_param('remove', 0, PARAM_BOOL);
- $showall = optional_param('showall', 0, PARAM_BOOL);
- $searchtext = optional_param('searchtext', '', PARAM_RAW); // search string
+ $contextid = required_param('contextid',PARAM_INT);
+ $roleid = optional_param('roleid', 0, PARAM_INT);
+ $userid = optional_param('userid', 0, PARAM_INT); // needed for user tabs
+ $courseid = optional_param('courseid', 0, PARAM_INT); // needed for user tabs
$hidden = optional_param('hidden', 0, PARAM_BOOL); // whether this assignment is hidden
$extendperiod = optional_param('extendperiod', 0, PARAM_INT);
$extendbase = optional_param('extendbase', 0, PARAM_INT);
- $userid = optional_param('userid', 0, PARAM_INT); // needed for user tabs
- $courseid = optional_param('courseid', 0, PARAM_INT); // needed for user tabs
$errors = array();
- $baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/role/assign.php?contextid=' . $contextid;
+ $baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/roles/assign.php?contextid=' . $contextid;
if (!empty($userid)) {
$baseurl .= '&userid='.$userid;
}
$course = clone($SITE);
}
+/// Check login and permissions.
require_login($course);
-
require_capability('moodle/role:assign', $context);
-/// needed for tabs.php
-
+/// These are needed early because of tabs.php
$overridableroles = get_overridable_roles($context, ROLENAME_BOTH);
list($assignableroles, $assigncounts, $nameswithcounts) = get_assignable_roles($context, ROLENAME_BOTH, true);
-/// Get some language strings
+/// Make sure this user can assign this role
+ if ($roleid && !isset($assignableroles[$roleid])) {
+ $a = stdClass;
+ $a->role = $roleid;
+ $a->context = $contextname;
+ print_error('cannotassignrolehere', '', get_context_url($context), $a);
+ }
+/// Get some language strings
$strpotentialusers = get_string('potentialusers', 'role');
$strexistingusers = get_string('existingusers', 'role');
$straction = get_string('assignroles', 'role');
$strparticipants = get_string('participants');
$strsearchresults = get_string('searchresults');
+/// Build the list of options for the enrolment period dropdown.
$unlimitedperiod = get_string('unlimited');
$defaultperiod = $course->enrolperiod;
for ($i=1; $i<=365; $i++) {
$periodmenu[$seconds] = get_string('numdays', '', $i);
}
+/// Build the list of options for the starting from dropdown.
$timeformat = get_string('strftimedate');
$today = time();
$today = make_timestamp(date('Y', $today), date('m', $today), date('d', $today), 0, 0, 0);
}
}
-/// Make sure this user can assign this role
-
- if ($roleid) {
- if (!isset($assignableroles[$roleid])) {
- error ('you can not override this role in this context');
- }
- }
-
- if ($userid) {
+/// Print the header and tabs
+ if ($context->contextlevel == CONTEXT_USER) {
$user = $DB->get_record('user', array('id'=>$userid));
$fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
- }
-
-/// Print the header and tabs
-
- if ($context->contextlevel == CONTEXT_USER) {
/// course header
$navlinks = array();
if ($courseid != SITEID) {
$showroles = 1;
$currenttab = 'assign';
include_once($CFG->dirroot.'/user/tabs.php');
+
} else if ($context->contextlevel == CONTEXT_SYSTEM) {
admin_externalpage_setup('assignroles');
admin_externalpage_print_header();
- } else if ($context->contextlevel==CONTEXT_COURSE and $context->instanceid == SITEID) {
+
+ } else if ($context->contextlevel == CONTEXT_COURSE and $context->instanceid == SITEID) {
admin_externalpage_setup('frontpageroles');
admin_externalpage_print_header();
$currenttab = 'assign';
include_once('tabs.php');
+
} else {
$currenttab = 'assign';
include_once('tabs.php');
}
-
-/// Process incoming role assignment
-
- if ($frm = data_submitted()) {
-
- if ($add and !empty($frm->addselect) and confirm_sesskey()) {
-
- foreach ($frm->addselect as $adduser) {
- if (!$adduser = clean_param($adduser, PARAM_INT)) {
- continue;
- }
- $allow = true;
- if ($inmeta) {
- if (has_capability('moodle/course:managemetacourse', $context, $adduser)) {
- //ok
- } else {
- $managerroles = get_roles_with_capability('moodle/course:managemetacourse', CAP_ALLOW, $context);
- if (!empty($managerroles) and !array_key_exists($roleid, $managerroles)) {
- $erruser = $DB->get_record('user', array('id'=>$adduser), 'id, firstname, lastname');
- $errors[] = get_string('metaassignerror', 'role', fullname($erruser));
- $allow = false;
- }
- }
- }
- if ($allow) {
- switch($extendbase) {
- case 0:
- $timestart = $course->startdate;
- break;
- case 3:
- $timestart = $today;
- break;
- case 4:
- $timestart = $course->enrolstartdate;
- break;
- case 5:
- $timestart = $course->enrolenddate;
- break;
- }
-
- if($extendperiod > 0) {
- $timeend = $timestart + $extendperiod;
- } else {
- $timeend = 0;
- }
- if (! role_assign($roleid, $adduser, 0, $context->id, $timestart, $timeend, $hidden)) {
- $errors[] = "Could not add user with id $adduser to this role!";
- }
- }
- }
-
- $rolename = $DB->get_field('role', 'name', array('id'=>$roleid));
- add_to_log($course->id, 'role', 'assign', 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
- } else if ($remove and !empty($frm->removeselect) and confirm_sesskey()) {
-
- $sitecontext = get_context_instance(CONTEXT_SYSTEM);
- $topleveladmin = false;
-
- // we only worry about this if the role has doanything capability at site level
- if ($context->id == $sitecontext->id && $adminroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $sitecontext)) {
- foreach ($adminroles as $adminrole) {
- if ($adminrole->id == $roleid) {
- $topleveladmin = true;
- }
- }
- }
-
- foreach ($frm->removeselect as $removeuser) {
- $removeuser = clean_param($removeuser, PARAM_INT);
-
- if ($topleveladmin && ($removeuser == $USER->id)) { // Prevent unassigning oneself from being admin
- continue;
- }
-
- if (! role_unassign($roleid, $removeuser, 0, $context->id)) {
- $errors[] = "Could not remove user with id $removeuser from this role!";
- } else if ($inmeta) {
- sync_metacourse($courseid);
- $newroles = get_user_roles($context, $removeuser, false);
- if (!empty($newroles) and !array_key_exists($roleid, $newroles)) {
- $erruser = $DB->get_record('user', array('id'=>$removeuser), 'id, firstname, lastname');
- $errors[] = get_string('metaunassignerror', 'role', fullname($erruser));
- $allow = false;
- }
- }
- }
-
- $rolename = $DB->get_field('role', 'name', array('id'=>$roleid));
- add_to_log($course->id, 'role', 'unassign', 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
- } else if ($showall) {
- $searchtext = '';
- }
- }
-
+/// Print heading.
if ($isfrontpage) {
print_heading_with_help(get_string('frontpageroles', 'admin'), 'assignroles');
} else {
print_heading_with_help(get_string('assignrolesin', 'role', $contextname), 'assignroles');
}
- if ($context->contextlevel==CONTEXT_SYSTEM) {
+/// Print a warning if we are assigning system roles.
+ if ($context->contextlevel == CONTEXT_SYSTEM) {
print_box(get_string('globalroleswarning', 'role'));
}
- if ($roleid) {
+ if ($roleid) { /// UI for assigning a particular role.
- /// Get all existing participants in this context.
- // Why is this not done with get_users???
-
- if (!$contextusers = get_role_users($roleid, $context, false, 'u.id, u.firstname, u.lastname, u.email, ra.hidden')) {
- $contextusers = array();
+ /// Create the user selector objects.
+ $options = array('context' => $context, 'roleid' => $roleid);
+ if ($context->contextlevel > CONTEXT_COURSE) {
+ $potentialuserselector = new potential_assignees_below_course('addselect', $options);
+ } else {
+ $potentialuserselector = new potential_assignees_course_and_above('addselect', $options);
+ }
+ if ($context->contextlevel == CONTEXT_SYSTEM && is_admin_role($roleid)) {
+ $currentuserselector = new existing_role_holders_site_admin('removeselect', $options);
+ } else {
+ $currentuserselector = new existing_role_holders('removeselect', $options);
}
- $select = "username <> 'guest' AND deleted = 0 AND confirmed = 1";
- $params = array();
+ /// Process incoming role assignments
+ if (optional_param('add', false, PARAM_BOOL) && confirm_sesskey()) {
+ $userstoassign = $potentialuserselector->get_selected_users();
+ if (!empty($userstoassign)) {
+
+ foreach ($userstoassign as $adduser) {
+ $allow = true;
+ if ($inmeta) {
+ if (has_capability('moodle/course:managemetacourse', $context, $adduser->id)) {
+ //ok
+ } else {
+ $managerroles = get_roles_with_capability('moodle/course:managemetacourse', CAP_ALLOW, $context);
+ if (!empty($managerroles) and !array_key_exists($roleid, $managerroles)) {
+ $erruser = $DB->get_record('user', array('id'=>$adduser->id), 'id, firstname, lastname');
+ $errors[] = get_string('metaassignerror', 'role', fullname($erruser));
+ $allow = false;
+ }
+ }
+ }
- $usercount = $DB->count_records_select('user', $select, $params) - count($contextusers);
+ if ($allow) {
+ switch($extendbase) {
+ case 0:
+ $timestart = $course->startdate;
+ break;
+ case 3:
+ $timestart = $today;
+ break;
+ case 4:
+ $timestart = $course->enrolstartdate;
+ break;
+ case 5:
+ $timestart = $course->enrolenddate;
+ break;
+ }
- $searchtext = trim($searchtext);
+ if($extendperiod > 0) {
+ $timeend = $timestart + $extendperiod;
+ } else {
+ $timeend = 0;
+ }
+ if (! role_assign($roleid, $adduser->id, 0, $context->id, $timestart, $timeend, $hidden)) {
+ $a = new stdClass;
+ $a->role = $rolenames[$roleid];
+ $a->user = fullname($adduser);
+ $errors[] = get_string('assignerror', 'role', $a);
+ }
+ }
+ }
- if ($searchtext !== '') { // Search for a subset of remaining users
- $LIKE = $DB->sql_ilike();
- $FULLNAME = $DB->sql_fullname();
+ $potentialuserselector->invalidate_selected_users();
+ $currentuserselector->invalidate_selected_users();
- $select .= " AND ($FULLNAME $LIKE :search1 OR email $LIKE :search2) ";
- $params['search1'] = "%$searchtext%";
- $params['search2'] = "%$searchtext%";
+ $rolename = $DB->get_field('role', 'name', array('id'=>$roleid));
+ add_to_log($course->id, 'role', 'assign', 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
+ }
}
- if ($context->contextlevel > CONTEXT_COURSE) { // mod or block (or group?)
-
- /************************************************************************
- * *
- * context level is above or equal course context level *
- * in this case we pull out all users matching search criteria (if any) *
- * *
- * MDL-11324 *
- * a mini get_users_by_capability() call here, this is done instead of *
- * get_users_by_capability() because *
- * 1) get_users_by_capability() does not deal with searching by name *
- * 2) exceptions array can be potentially large for large courses *
- * 3) $DB->get_recordset_sql() is more efficient *
- * *
- ************************************************************************/
-
- if ($possibleroles = get_roles_with_capability('moodle/course:view', CAP_ALLOW, $context)) {
-
- $doanythingroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, get_context_instance(CONTEXT_SYSTEM));
-
- $validroleids = array();
- foreach ($possibleroles as $possiblerole) {
- if (isset($doanythingroles[$possiblerole->id])) { // We don't want these included
- continue;
- }
- if ($caps = role_context_capabilities($possiblerole->id, $context, 'moodle/course:view')) { // resolved list
- if (isset($caps['moodle/course:view']) && $caps['moodle/course:view'] > 0) { // resolved capability > 0
- $validroleids[] = $possiblerole->id;
+ /// Process incoming role unassignments
+ if (optional_param('remove', false, PARAM_BOOL) && confirm_sesskey()) {
+ $userstounassign = $currentuserselector->get_selected_users();
+ if (!empty($userstounassign)) {
+
+ foreach ($userstounassign as $removeuser) {
+ if (! role_unassign($roleid, $removeuser->id, 0, $context->id)) {
+ $a = new stdClass;
+ $a->role = $rolenames[$roleid];
+ $a->user = fullname($removeuser);
+ $errors[] = get_string('unassignerror', 'role', $a);
+ } else if ($inmeta) {
+ sync_metacourse($courseid);
+ $newroles = get_user_roles($context, $removeuser->id, false);
+ if (empty($newroles) || array_key_exists($roleid, $newroles)) {
+ $errors[] = get_string('metaunassignerror', 'role', fullname($removeuser));
}
}
}
- if ($validroleids) {
- $roleids = '('.implode(',', $validroleids).')';
-
- $fields = "SELECT u.id, u.firstname, u.lastname, u.email";
- $countfields = "SELECT COUNT('x')";
-
- $sql = " FROM {user} u
- JOIN {role_assignments} ra ON ra.userid = u.id
- JOIN {role} r ON r.id = ra.roleid
- WHERE ra.contextid ".get_related_contexts_string($context)."
- AND $select AND ra.roleid in $roleids
- AND u.id NOT IN (
- SELECT u.id
- FROM {role_assignments} r, {user} u
- WHERE r.contextid = :contextid
- AND u.id = r.userid
- AND r.roleid = :roleid)";
- $params['contextid'] = $contextid;
- $params['roleid'] = $roleid;
-
- $availableusers = $DB->get_recordset_sql("$fields $sql", $params);
- $usercount = $DB->count_records_sql("$countfields $sql", $params);
-
- } else {
- $availableusers = array();
- $usercount = 0;
- }
- }
-
- } else {
+ $potentialuserselector->invalidate_selected_users();
+ $currentuserselector->invalidate_selected_users();
- /************************************************************************
- * *
- * context level is above or equal course context level *
- * in this case we pull out all users matching search criteria (if any) *
- * *
- ************************************************************************/
-
- /// MDL-11111 do not include user already assigned this role in this context as available users
- /// so that the number of available users is right and we save time looping later
- $fields = "SELECT id, firstname, lastname, email";
- $countfields = "SELECT COUNT('x')";
-
- $sql = " FROM {user}
- WHERE $select
- AND id NOT IN (
- SELECT u.id
- FROM {role_assignments} r, {user} u
- WHERE r.contextid = :contextid
- AND u.id = r.userid
- AND r.roleid = :roleid)";
- $order = "ORDER BY lastname ASC, firstname ASC";
-
- $params['contextid'] = $contextid;
- $params['roleid'] = $roleid;
-
- $availableusers = $DB->get_recordset_sql("$fields $sql $order", $params);
- $usercount = $DB->count_records_sql("$countfields $sql", $params);
+ $rolename = $DB->get_field('role', 'name', array('id'=>$roleid));
+ add_to_log($course->id, 'role', 'unassign', 'admin/roles/assign.php?contextid='.$context->id.'&roleid='.$roleid, $rolename, '', $USER->id);
+ }
}
- print_simple_box_start('center');
- include('assign.html');
- print_simple_box_end();
+ /// Print the form.
+ check_theme_arrows();
+?>
+<form id="assignform" method="post" action="<?php echo $baseurl . '&roleid=' . $roleid ?>">
+<input type="hidden" name="sesskey" value="<?php echo sesskey() ?>" />
+
+ <table summary="" class="roleassigntable generaltable generalbox boxaligncenter" cellspacing="0">
+ <tr>
+ <td id="existingcell">
+ <p><label for="removeselect"><?php print_string('extusers', 'role'); ?></label></p>
+ <?php $currentuserselector->display() ?>
+ </td>
+ <td id="buttonscell">
+ <div id="addcontrols">
+ <input name="add" id="add" type="submit" value="<?php echo $THEME->larrow.' '.get_string('add'); ?>" title="<?php print_string('add'); ?>" /><br />
+
+ <p><input type="checkbox" name="hidden" id="hidden" value="1" <?php
+ if ($hidden) { echo 'checked="checked" '; } ?>/>
+ <label for="hidden" title="<?php print_string('createhiddenassign', 'role'); ?>">
+ <?php print_string('hidden', 'role'); ?>
+ <?php helpbutton('hiddenassign', get_string('createhiddenassign', 'role')); ?>
+ </label></p>
+
+ <p><label for="extendperiod"><?php print_string('enrolperiod') ?></label><br />
+ <?php choose_from_menu($periodmenu, "extendperiod", $defaultperiod, $unlimitedperiod); ?></p>
+
+ <p><label for="extendbase"><?php print_string('startingfrom') ?></label><br />
+ <?php choose_from_menu($basemenu, "extendbase", 3, ""); ?></p>
+ </div>
+
+ <div id="removecontrols">
+ <input name="remove" id="remove" type="submit" value="<?php echo get_string('remove').' '.$THEME->rarrow; ?>" title="<?php print_string('remove'); ?>" />
+ </div>
+ </td>
+ <td id="potentialcell">
+ <p><label for="addselect"><?php print_string('potusers', 'role'); ?></label></p>
+ <?php $potentialuserselector->display() ?>
+ </td>
+ </tr>
+ </table>
+</form>
+
+<?php
+ print_js_call('init_add_assign_page');
if (!empty($errors)) {
$msg = '<p>';
}
// Get the names of role holders for roles with between 1 and MAX_USERS_TO_LIST_PER_ROLE users,
- // and so determine whether to show the extra column.
+ // and so determine whether to show the extra column.
$rolehodlernames = array();
$strmorethanmax = get_string('morethan', 'role', MAX_USERS_TO_LIST_PER_ROLE);
$showroleholders = false;
}
}
};
+
+function init_add_assign_page() {
+ var addselect = user_selector.get('addselect');
+ document.getElementById('add').disabled = addselect.is_selection_empty();
+ addselect.subscribe('selectionchanged', function(isempty) {
+ document.getElementById('add').disabled = isempty;
+ });
+
+ var removeselect = user_selector.get('removeselect');
+ document.getElementById('remove').disabled = removeselect.is_selection_empty();
+ removeselect.subscribe('selectionchanged', function(isempty) {
+ document.getElementById('remove').disabled = isempty;
+ });
+}
\ No newline at end of file
<table class="generaltable generalbox groupmanagementtable boxaligncenter" summary="">
<tr>
- <td id='memberscell'>
+ <td id='existingcell'>
<p>
<label for="removeselect"><?php print_string('groupmembers', 'group'); ?></label>
</p>
<input name="remove" id="remove" type="submit" value="<?php echo get_string('remove').' '.$THEME->rarrow; ?>" title="<?php print_string('remove'); ?>" />
</p>
</td>
- <td id='nonmemberscell'>
+ <td id='potentialcell'>
<p>
<label for="addselect"><?php print_string('potentialmembs', 'group'); ?></label>
</p>
$string['cannotaddmodule'] = '$a module could not be added to the module list!';
$string['cannotaddnewmodule'] = 'Could not add a new module of $a';
$string['cannotaddnewinstance'] = 'Could not add a new instance of $a';
+$string['cannotassignrolehere'] = 'You are not allowed to assign this role (id = $a->roleid) in this context ($a->context)';
$string['cannotsaveconfig'] = 'Problem saving config \"$a->name\" as \"$a->value\" for plugin \"$a->plugin\"';
$string['cannotsavecomment'] = 'Cannot save comment';
$string['cannotsavefile'] = 'Cannot save the file \"$a\"!';
$string['allowoverride'] = 'Allow role overrides';
$string['allsiteusers'] = 'All site users';
$string['assignanotherrole'] = 'Assign another role';
+$string['assignerror'] = 'Error while assigning the role $a->role to user $a->user.';
$string['assignroles'] = 'Assign roles';
$string['assignrolesin'] = 'Assign roles in $a';
$string['assignglobalroles'] = 'Assign system roles';
$string['course:viewparticipants'] = 'View participants';
$string['course:viewscales'] = 'View scales';
$string['course:visibility'] = 'Hide/show courses';
+$string['createhiddenassign'] = 'Create hidden role assignments';
$string['deletecourseoverrides'] = 'Delete all overrides in course';
$string['deletelocalroles'] = 'Delete all local role assignments';
$string['grade:edit'] = 'Edit grades';
$string['explainpermissionsdetails'] = 'For capability $a->capability in context $a->context when logged in as $a->fullname.';
$string['explainpermissionsinfo'] = '<p>To use this table:</p><ol><li>First look to see if there are any Prohibits. If there are, has_capability will return false.</li><li>Otherwise, read across the rows, left-to-right, top-to-bottom, and find the first cell where the number of Prevents and Allows are different. If there are more Allows than Prevents in that cell, then has_capability will return true, otherwise it will return false.</li><li>If no cell has different numbers of Prevents and Allows, then has_capability will return false.</li></ol>';
$string['explainpermissionsdoanything'] = 'Note that this user has the moodle/site:doanything capability, so even though the table above shows that has_capability will return false, this user will actually be deemed to have the capability $a in most circumstances.';
+$string['extusers'] = 'Existing users';
+$string['extusersmatching'] = 'Existing users matching \'$a\'';
$string['globalrole'] = 'System role';
$string['globalroleswarning'] = 'WARNING! Any roles you assign from this page will apply to the assigned users throughout the entire system, including the front page and all the courses.';
+$string['hidden'] = 'Hidden';
$string['inherit'] = 'Inherit';
$string['legacy:admin'] = 'LEGACY ROLE: Administrator';
$string['legacy:coursecreator'] = 'LEGACY ROLE: Course Creator';
$string['overrides'] = 'Overrides';
$string['permissions'] = 'Permissions';
$string['potentialusers'] = '$a potential users';
+$string['potusers'] = 'Potential users';
+$string['potusersmatching'] = 'Potential users matching \'$a\'';
$string['portfolio:export'] = 'Export to portfolios';
$string['prevent'] = 'Prevent';
$string['prohibit'] = 'Prohibit';
$string['tag:create'] = 'Create new tags';
$string['tag:edit'] = 'Edit existing tags';
$string['tag:editblocks'] = 'Edit blocks in tags pages';
+$string['unassignerror'] = 'Error while unassigning the role $a->role from user $a->user.';
$string['user:changeownpassword'] = 'Change own password';
$string['user:create'] = 'Create users';
$string['user:delete'] = 'Delete users';
return $DB->record_exists_sql($sql, $params);
}
+/**
+ * @param integer $roleid a role id.
+ * @return boolean, whether this role is an admin role.
+ */
+function is_admin_role($roleid) {
+ global $CFG, $DB;
+
+ $sql = "SELECT 1
+ FROM {role_capabilities} rc
+ JOIN {context} ctx ON ctx.id = rc.contextid
+ WHERE ctx.contextlevel = 10
+ AND rc.roleid = ?
+ AND rc.capability IN (?, ?, ?)
+ GROUP BY rc.capability
+ HAVING SUM(rc.permission) > 0";
+ $params = array($roleid, 'moodle/site:config', 'moodle/legacy:admin', 'moodle/site:doanything');
+
+ return $DB->record_exists_sql($sql, $params);
+}
+
function get_course_from_path ($path) {
// assume that nothing is more than 1 course deep
if (preg_match('!^(/.+)/\d+$!', $path, $matches)) {
* @param bool gethidden - whether to fetch hidden enrolments too
* @return array()
*/
-function get_role_users($roleid, $context, $parent=false, $fields='', $sort='u.lastname ASC', $gethidden=true, $group='', $limitfrom='', $limitnum='') {
+function get_role_users($roleid, $context, $parent=false, $fields='',
+ $sort='u.lastname, u.firstname', $gethidden=true, $group='',
+ $limitfrom='', $limitnum='', $extrawheretest='', $whereparams=array()) {
global $DB;
if (empty($fields)) {
array_unshift($params, $context->id);
+ if ($extrawheretest) {
+ $extrawheretest = ' AND ' . $extrawheretest;
+ $params = array_merge($params, $whereparams);
+ }
+
$sql = "SELECT $fields, ra.roleid
FROM {role_assignments} ra
JOIN {user} u ON u.id = ra.userid
$roleselect
$groupselect
$hiddensql
+ $extrawheretest
ORDER BY $sort"; // join now so that we can just use fullname() later
return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
.groupmanagementtable {
width: 90%;
}
-
.groupmanagementtable td {
vertical-align: middle;
}
-
.groupmanagementtable p {
- text-align: center;
+ text-align: left;
+ margin-bottom: 0.2em;
}
-
-.groupmanagementtable #memberscell,
-.groupmanagementtable #nonmemberscell {
+.groupmanagementtable #existingcell,
+.groupmanagementtable #potentialcell {
width: 42%;
}
-.groupmanagementtable #memberscell label,
-.groupmanagementtable #nonmemberscell label {
+.groupmanagementtable #existingcell label,
+.groupmanagementtable #potentialcell label {
font-weight: bold;
}
.groupmanagementtable #buttonscell {
width: 16%;
}
+.groupmanagementtable #buttonscell p {
+ text-align: center;
+}
.groupmanagementtable #buttonscell input {
width: 80%;
padding: 1em 0;
- margin: 2em 0;
+}
+.groupmanagementtable #buttonscell #remove {
+ margin: 7em 0;
}
.groupmanagementtable #backcell {
padding-top: 2em;
text-align: center;
}
-#removeselect_wrapper,
-#addselect_wrapper {
+.groupmanagementtable #removeselect_wrapper,
+.groupmanagementtable #addselect_wrapper {
width: 100%;
}
.groupmanagementtable #removeselect_wrapper label,
.userselector select {
width: 100%;
}
+.userselector div {
+ margin-top: 0.2em;
+}
.userselector div label {
margin-right: 0.3em;
}
padding: 5px;
}
-#admin-roles-manage .selector,
-#admin-roles-assign .selector,
-#admin-roles-override .selector {
- text-align:center;
- margin-bottom:1em;
+.roleassigntable {
+ width: 100%;
+}
+.roleassigntable td {
+ vertical-align: middle;
+ padding: 0 0.3em 1em;
+}
+.roleassigntable p {
+ text-align: left;
+ margin-bottom: 0.2em;
+}
+.roleassigntable #existingcell,
+.roleassigntable #potentialcell {
+ width: 38%;
+}
+.roleassigntable #existingcell label,
+.roleassigntable #potentialcell label {
+ font-weight: bold;
+}
+.roleassigntable #buttonscell {
+ width: 24%;
+}
+.roleassigntable #buttonscell #add,
+.roleassigntable #buttonscell #remove {
+ width: 100%;
+ margin: 0.3em 0;
+ padding: 0.5em 0;
+}
+.roleassigntable #buttonscell p {
+ margin: 0.3em 0;
+}
+.roleassigntable #buttonscell #remove {
+ margin-top: 5em;
+}
+.roleassigntable #removeselect_wrapper,
+.roleassigntable #addselect_wrapper {
+ width: 100%;
+}
+.roleassigntable #removeselect_wrapper label,
+.roleassigntable #addselect_wrapper label {
+ font-weight: normal;
}
#admin-roles-manage table.roledesc,
public function __construct($name, $options = array()) {
global $CFG;
$this->name = $name;
- if (empty($CFG->extrauserselectorfields)) {
- $this->extrafields = array();
- } else {
+ if (isset($options['extrafields'])) {
+ $this->extrafields = $options['extrafields'];
+ } else if (!empty($CFG->extrauserselectorfields)) {
$this->extrafields = explode(',', $CFG->extrauserselectorfields);
+ } else {
+ $this->extrafields = array();
}
if (isset($options['exclude']) && is_array($options['exclude'])) {
$this->exclude = $options['exclude'];
}
/**
- * @return array the userids that were selected. This is a more sophisticated version
+ * @return array of user objects. The users that were selected. This is a more sophisticated version
* of optional_param($this->name, array(), PARAM_INTEGER) that validates the
* returned list of ids against the rules for this user selector.
*/
* array should be the string names of optgroups. The keys of the inner
* arrays should be userids, and the values should be user objects
* containing at least the list of fields returned by the method
- * required_fields_sql().
+ * required_fields_sql(). If a user object has a ->disabled property
+ * that is true, then that option will be displayed greyed out, and
+ * will not be returned by get_selected_users.
*/
public abstract function find_users($search);
'class' => get_class($this),
'name' => $this->name,
'exclude' => $this->exclude,
+ 'extrafields' => $this->extrafields
);
}
// Aggregate the resulting list back into a single one.
$users = array();
foreach ($groupedusers as $group) {
- $users += $group;
+ foreach ($group as $user) {
+ if (!isset($users[$user->id]) && empty($user->disabled)) {
+ $users[$user->id] = $user;
+ }
+ }
}
// If we are only supposed to be selecting a single user, make sure we do.
$params = array();
$tests = array();
+ if ($u) {
+ $u .= '.';
+ }
+
// If we have a $search string, put a field LIKE '$search%' condition on each field.
if ($search) {
$conditions = array(
- $DB->sql_fullname($u . '.firstname', $u . '.lastname'),
- $conditions[] = $u . '.lastname'
+ $DB->sql_fullname($u . 'firstname', $u . 'lastname'),
+ $conditions[] = $u . 'lastname'
);
foreach ($this->extrafields as $field) {
- $conditions[] = $u . '.' . $field;
+ $conditions[] = $u . $field;
}
$ilike = ' ' . $DB->sql_ilike() . ' ?';
foreach ($conditions as &$condition) {
$tests[] = '(' . implode(' OR ', $conditions) . ')';
}
+ // Add some additional sensible conditions
+ $tests[] = $u . "username <> 'guest'";
+ $tests[] = $u . 'deleted = 0';
+ $tests[] = $u . 'confirmed = 1';
+
// If we are being asked to exclude any users, do that.
if (!empty($this->exclude)) {
list($usertest, $userparams) = $DB->get_in_or_equal($this->exclude, SQL_PARAMS_QM, '', false);
- $tests[] = $u . '.id ' . $usertest;
+ $tests[] = $u . 'id ' . $usertest;
$params = array_merge($params, $userparams);
}
// If we are validating a set list of userids, add an id IN (...) test.
if (!empty($this->validatinguserids)) {
list($usertest, $userparams) = $DB->get_in_or_equal($this->validatinguserids);
- $tests[] = $u . '.id ' . $usertest;
+ $tests[] = $u . 'id ' . $usertest;
$params = array_merge($params, $userparams);
}
if (!empty($users)) {
$output = ' <optgroup label="' . s($groupname) . ' (' . count($users) . ')">' . "\n";
foreach ($users as $user) {
- if ($select || isset($this->selected[$user->id])) {
- $selectattr = ' selected="selected"';
- } else {
- $selectattr = '';
+ $attributes = '';
+ if (!empty($user->disabled)) {
+ $attributes .= ' disabled="disabled"';
+ } else if ($select || isset($this->selected[$user->id])) {
+ $attributes .= ' selected="selected"';
}
unset($this->selected[$user->id]);
- $output .= ' <option' . $selectattr . ' value="' . $user->id . '">' .
+ $output .= ' <option' . $attributes . ' value="' . $user->id . '">' .
$this->output_user($user) . "</option>\n";
}
} else {
* @param object $user the user to display.
* @return string a string representation of the user.
*/
- protected function output_user($user) {
+ public function output_user($user) {
$bits = array(
fullname($user)
);
}
}
+// User selectors for managing role assignments ================================
+
+/**
+ * Base class to avoid duplicating code.
+ */
+abstract class role_assign_user_selector_base extends user_selector_base {
+ const MAX_USERS_PER_PAGE = 100;
+
+ protected $roleid;
+ protected $context;
+
+ /**
+ * @param string $name control name
+ * @param array $options should have two elements with keys groupid and courseid.
+ */
+ public function __construct($name, $options) {
+ global $CFG;
+ parent::__construct($name, $options);
+ $this->roleid = $options['roleid'];
+ if (isset($options['context'])) {
+ $this->context = $options['context'];
+ } else {
+ $this->context = get_context_instance_by_id($options['contextid']);
+ }
+ require_once($CFG->dirroot . '/group/lib.php');
+ }
+
+ protected function get_options() {
+ $options = parent::get_options();
+ $options['roleid'] = $this->roleid;
+ $options['contextid'] = $this->context->id;
+ return $options;
+ }
+}
+
/**
- * User selector subclass for the list of potential users on the assign roles page.
+ * User selector subclass for the list of potential users on the assign roles page,
+ * when we are assigning in a context below the course level. (CONTEXT_MODULE and
+ * CONTEXT_BLOCK).
*
+ * In this case we replicate part of get_users_by_capability() get the users
+ * with moodle/course:view (or moodle/site:doanything). We can't use
+ * get_users_by_capability() becuase
+ * 1) get_users_by_capability() does not deal with searching by name
+ * 2) exceptions array can be potentially large for large courses
*/
-class role_assign_potential_user_selector extends user_selector_base {
+class potential_assignees_below_course extends role_assign_user_selector_base {
public function find_users($search) {
- return array(); // TODO
+ global $DB;
+
+ // Get roles with some assignement to the 'moodle/course:view' capability.
+ $possibleroles = get_roles_with_capability('moodle/course:view', CAP_ALLOW, $this->context);
+ if (empty($possibleroles)) {
+ // If there aren't any, we are done.
+ return array();
+ }
+
+ // Now exclude the admin roles, and check the actual permission on
+ // 'moodle/course:view' to make sure it is allow.
+ $doanythingroles = get_roles_with_capability('moodle/site:doanything',
+ CAP_ALLOW, get_context_instance(CONTEXT_SYSTEM));
+ $validroleids = array();
+
+ foreach ($possibleroles as $possiblerole) {
+ if (isset($doanythingroles[$possiblerole->id])) {
+ continue;
+ }
+
+ if ($caps = role_context_capabilities($possiblerole->id, $this->context, 'moodle/course:view')) { // resolved list
+ if (isset($caps['moodle/course:view']) && $caps['moodle/course:view'] > 0) { // resolved capability > 0
+ $validroleids[] = $possiblerole->id;
+ }
+ }
+ }
+
+ // If there are no valid roles, we are done.
+ if (!$validroleids) {
+ return array();
+ }
+
+ // Now we have to go to the database.
+ list($wherecondition, $params) = $this->search_sql($search, 'u');
+ if ($wherecondition) {
+ $wherecondition = ' AND ' . $wherecondition;
+ }
+ $roleids = '('.implode(',', $validroleids).')';
+
+ $fields = 'SELECT ' . $this->required_fields_sql('u');
+ $countfields = 'SELECT COUNT(1)';
+
+ $sql = " FROM {user} u
+ JOIN {role_assignments} ra ON ra.userid = u.id
+ JOIN {role} r ON r.id = ra.roleid
+ WHERE ra.contextid " . get_related_contexts_string($this->context)."
+ $wherecondition
+ AND ra.roleid IN $roleids
+ AND u.id NOT IN (
+ SELECT u.id
+ FROM {role_assignments} r, {user} u
+ WHERE r.contextid = ?
+ AND u.id = r.userid
+ AND r.roleid = ?)";
+ $order = ' ORDER BY lastname ASC, firstname ASC';
+
+ $params[] = $this->context->id;
+ $params[] = $this->roleid;
+
+ // Check to see if there are too many to show sensibly.
+ $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params);
+ if ($potentialmemberscount > role_assign_user_selector_base::MAX_USERS_PER_PAGE) {
+ return array(get_string('toomanytoshow') => array(),
+ get_string('trysearching') => array());
+ }
+
+ // If not, show them.
+ $availableusers = $DB->get_records_sql($fields . $sql . $order, $params);
+
+ if (empty($availableusers)) {
+ return array();
+ }
+
+ if ($search) {
+ $groupname = get_string('potusersmatching', 'role', $search);
+ } else {
+ $groupname = get_string('potusers', 'role');
+ }
+
+ return array($groupname => $availableusers);
+ }
+}
+
+/**
+ * User selector subclass for the list of potential users on the assign roles page,
+ * when we are assigning in a context at or above the course level. In this case we
+ * show all the users in the system who do not already have the role.
+ */
+class potential_assignees_course_and_above extends role_assign_user_selector_base {
+ public function find_users($search) {
+ global $DB;
+
+ list($wherecondition, $params) = $this->search_sql($search, '');
+
+ $fields = 'SELECT ' . $this->required_fields_sql('');
+ $countfields = 'SELECT COUNT(1)';
+
+ $sql = " FROM {user}
+ WHERE $wherecondition
+ AND id NOT IN (
+ SELECT u.id
+ FROM {role_assignments} r, {user} u
+ WHERE r.contextid = ?
+ AND u.id = r.userid
+ AND r.roleid = ?)";
+ $order = ' ORDER BY lastname ASC, firstname ASC';
+
+ $params[] = $this->context->id;
+ $params[] = $this->roleid;
+
+ $potentialmemberscount = $DB->count_records_sql($countfields . $sql, $params);
+ if ($potentialmemberscount > role_assign_user_selector_base::MAX_USERS_PER_PAGE) {
+ return array(get_string('toomanytoshow') => array(),
+ get_string('trysearching') => array());
+ }
+
+ $availableusers = $DB->get_records_sql($fields . $sql . $order, $params);
+
+ if (empty($availableusers)) {
+ return array();
+ }
+
+ if ($search) {
+ $groupname = get_string('potusersmatching', 'role', $search);
+ } else {
+ $groupname = get_string('potusers', 'role');
+ }
+
+ return array($groupname => $availableusers);
}
}
* User selector subclass for the list of users who already have the role in
* question on the assign roles page.
*/
-class role_assign_current_user_selector extends user_selector_base {
+class existing_role_holders extends role_assign_user_selector_base {
+ protected $strhidden;
+
+ public function __construct($name, $options) {
+ parent::__construct($name, $options);
+ $this->strhidden = get_string('hiddenassign');
+ }
+
+ public function find_users($search) {
+ list($wherecondition, $params) = $this->search_sql($search, 'u');
+ $contextusers = get_role_users($this->roleid, $this->context, false,
+ $this->required_fields_sql('u') . ', ra.hidden', 'u.lastname, u.firstname',
+ true, '', '', '', $wherecondition, $params);
+
+ if (empty($contextusers)) {
+ return array();
+ }
+
+ if ($search) {
+ $groupname = get_string('extusersmatching', 'role', $search);
+ } else {
+ $groupname = get_string('extusers', 'role');
+ }
+
+ return array($groupname => $contextusers);
+ }
+
+ // Override to add (hidden) to hidden role assignments.
+ public function output_user($user) {
+ $output = parent::output_user($user);
+ if ($user->hidden) {
+ $output .= ' (' . $this->strhidden . ')';
+ }
+ return $output;
+ }
+}
+
+/**
+ * A special subclass to use when unassigning admins at site level. Disables
+ * the option for admins to unassign themselves.
+ */
+class existing_role_holders_site_admin extends existing_role_holders {
public function find_users($search) {
- return array(); // TODO
+ global $USER;
+ $groupeduses = parent::find_users($search);
+ foreach ($groupeduses as $group) {
+ foreach ($group as &$user) {
+ if ($user->id == $USER->id) {
+ $user->disabled = true;
+ }
+ }
+ }
+ return $groupeduses;
}
}
+// User selectors for managing group memebers ==================================
+
+/**
+ * Base class to avoid duplicating code.
+ */
abstract class groups_user_selector_base extends user_selector_base {
protected $groupid;
protected $courseid;
}
/**
- * Enter description here...
- *
* @param array $roles array in the format returned by groups_calculate_role_people.
* @return array array in the format find_users is supposed to return.
*/
class group_non_members_selector extends groups_user_selector_base {
const MAX_USERS_PER_PAGE = 100;
- protected function output_user($user) {
+ public function output_user($user) {
return parent::output_user($user) . ' (' . $user->numgroups . ')';
}
// If we are in developer debug mode, output a link to help debug the failure.
if (moodle_cfg.developerdebug) {
var link = document.createElement('a');
- link.href = this.searchurl + this.get_search_text();
+ link.href = this.searchurl + this.get_search_text() + '&debug=1';
link.appendChild(document.createTextNode('Ajax call failed. Click here to try the search call directly.'))
this.searchfield.parentNode.appendChild(link);
}
var option = options[0];
if (option.selected) {
var optiontext = option.innerText || option.textContent
- this.selected[option.value] = { id: option.value, formatted: optiontext };
+ this.selected[option.value] = { id: option.value, name: optiontext, disabled: option.disabled };
}
optgroup.removeChild(option);
}
var user = users[userid];
var option = document.createElement('option');
option.value = user.id;
- option.appendChild(document.createTextNode(this.output_user(user)));
- if (select || this.selected[user.id]) {
+ option.appendChild(document.createTextNode(user.name));
+ if (user.disabled) {
+ option.disabled = 'disabled';
+ } else if (select || this.selected[user.id]) {
option.selected = 'selected';
}
delete this.selected[user.id];
this.listbox.appendChild(optgroup);
}
-/**
- * Convert a user object to a string suitable for displaying as an option in the list box.
- *
- * @param Object user the user to display.
- * @return string a string representation of the user.
- */
-user_selector.prototype.output_user = function(user) {
- if (user.formatted) {
- return user.formatted;
- }
- var output = user.fullname;
- for (var i = 0; i < this.extrafields.length; i++) {
- output += ', ' + user[this.extrafields[i]];
- }
- return output;
-}
-
// Say that we want to be a source of custom events.
YAHOO.lang.augmentProto(user_selector, YAHOO.util.EventProvider);
\ No newline at end of file
require_once(dirname(__FILE__) . '/../../config.php');
require_once($CFG->dirroot . '/user/selector/lib.php');
+// In developer debug mode, when there is a debug=1 in the URL send as plain text
+// for easier debugging.
+if (debugging('', DEBUG_DEVELOPER) && optional_param('debug', false, PARAM_BOOL)) {
+ header('Content-type: text/plain; charset=UTF-8');
+ $debugmode = true;
+} else {
+ header('Content-type: application/json');
+ $debugmode = false;
+}
+
// Check access.
if (!isloggedin()) {;
print_error('mustbeloggedin');
print_error('unknownuserselector');
}
-// Create the appropriate userselector.
+// Get the options.
$options = $USER->userselectors[$selectorhash];
+
+if ($debugmode) {
+ echo 'Search string: ', $search, "\n";
+ echo 'Options: ';
+ print_r($options);
+ echo "\n";
+}
+
+// Create the appropriate userselector.
$classname = $options['class'];
unset($options['class']);
$name = $options['name'];
// Do the search and output the results.
$users = $userselector->find_users($search);
foreach ($users as &$group) {
- foreach ($group as &$user) {
- $user->fullname = fullname($user);
+ foreach ($group as $user) {
+ $output = new stdClass;
+ $output->id = $user->id;
+ $output->name = $userselector->output_user($user);
+ if (!empty($user->disabled)) {
+ $output->disabled = true;
+ }
+ $group[$user->id] = $output;
}
}
-
-header('Content-type: application/json');
echo json_encode(array('results' => $users));
?>
\ No newline at end of file