MDL-19756 Deprecated update_mymoodle_icon() and upgraded my/index.php with new output...
[moodle.git] / user / index.php
CommitLineData
f9903ed0 1<?PHP // $Id$
2
3// Lists all the users within a given course
4
cc038b47 5 require_once('../config.php');
68b38e8d 6 require_once($CFG->libdir.'/tablelib.php');
951b22a8 7
8 define('USER_SMALL_CLASS', 20); // Below this is considered small
9 define('USER_LARGE_CLASS', 200); // Above this is considered large
cc038b47 10 define('DEFAULT_PAGE_SIZE', 20);
36075e09 11 define('SHOW_ALL_PAGE_SIZE', 5000);
073af1a6 12 define('MODE_BRIEF', 0);
13 define('MODE_USERDETAILS', 1);
14 define('MODE_ENROLDETAILS', 2);
f9903ed0 15
cc038b47 16 $page = optional_param('page', 0, PARAM_INT); // which page to show
17 $perpage = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT); // how many per page
073af1a6 18 $mode = optional_param('mode', NULL); // use the MODE_ constants
5f9e296a 19 $accesssince = optional_param('accesssince',0,PARAM_INT); // filter by last access. -1 = never
ac17ef11 20 $search = optional_param('search','',PARAM_CLEAN);
5f9e296a 21 $roleid = optional_param('roleid', 0, PARAM_INT); // optional roleid, -1 means all site users on frontpage
e957cc26 22
5f9e296a 23 $contextid = optional_param('contextid', 0, PARAM_INT); // one of this or
24 $courseid = optional_param('id', 0, PARAM_INT); // this are required
8e127eb3 25
26 $PAGE->set_url('user/index.php', compact('page', 'perpage', 'mode', 'accesssince', 'search', 'roleid', 'contextid', 'courseid'));
f1e24e7a 27
e957cc26 28 if ($contextid) {
29 if (! $context = get_context_instance_by_id($contextid)) {
06e84d52 30 print_error('invalidcontext');
e957cc26 31 }
ce8c75ee 32 if (! $course = $DB->get_record('course', array('id'=>$context->instanceid))) {
06e84d52 33 print_error('invalidcourseid');
e957cc26 34 }
35 } else {
ce8c75ee 36 if (! $course = $DB->get_record('course', array('id'=>$courseid))) {
06e84d52 37 print_error('invalidcourseid');
e957cc26 38 }
39 if (! $context = get_context_instance(CONTEXT_COURSE, $course->id)) {
06e84d52 40 print_error('invalidcontext');
e957cc26 41 }
f9903ed0 42 }
87a13824 43 // not needed anymore
44 unset($contextid);
45 unset($courseid);
f9903ed0 46
224aa44a 47 require_login($course);
f9903ed0 48
1118434a 49 $systemcontext = get_context_instance(CONTEXT_SYSTEM);
165088f6 50 $frontpagectx = get_context_instance(CONTEXT_COURSE, SITEID);
224aa44a 51
165088f6 52 if ($context->id != $frontpagectx->id) {
b92adb86 53 require_capability('moodle/course:viewparticipants', $context);
165088f6 54 } else {
1118434a 55 require_capability('moodle/site:viewparticipants', $systemcontext);
5f9e296a 56 // override the default on frontpage
57 $roleid = optional_param('roleid', -1, PARAM_INT);
6d3c57f4 58 }
59
165088f6 60 /// front page course is different
6d3c57f4 61 $rolenames = array();
b373a751 62 $avoidroles = array();
6d3c57f4 63
64 if ($roles = get_roles_used_in_context($context, true)) {
0be6f678 65 // We should ONLY allow roles with moodle/course:view because otherwise we get little niggly issues
b373a751 66 // like MDL-8093
0be6f678 67 // We should further exclude "admin" users (those with "doanything" at site level) because
6d3c57f4 68 // Otherwise they appear in every participant list
69
b373a751 70 $canviewroles = get_roles_with_capability('moodle/course:view', CAP_ALLOW, $context);
1118434a 71 $doanythingroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $systemcontext);
41d7209c 72
5f9e296a 73 if ($context->id == $frontpagectx->id) {
74 //we want admins listed on frontpage too
75 foreach ($doanythingroles as $dar) {
76 $canviewroles[$dar->id] = $dar;
77 }
78 $doanythingroles = array();
79 }
80
41d7209c 81 foreach ($roles as $role) {
b373a751 82 if (!isset($canviewroles[$role->id])) { // Avoid this role (eg course creator)
83 $avoidroles[] = $role->id;
84 unset($roles[$role->id]);
85 continue;
86 }
6d3c57f4 87 if (isset($doanythingroles[$role->id])) { // Avoid this role (ie admin)
b373a751 88 $avoidroles[] = $role->id;
6d3c57f4 89 unset($roles[$role->id]);
90 continue;
91 }
0150c561 92 $rolenames[$role->id] = strip_tags(role_get_name($role, $context)); // Used in menus etc later on
41d7209c 93 }
6d3c57f4 94 }
95
5f9e296a 96 if ($context->id == $frontpagectx->id and $CFG->defaultfrontpageroleid) {
97 // default frontpage role is assigned to all site users
98 unset($rolenames[$CFG->defaultfrontpageroleid]);
99 }
100
101 // no roles to display yet?
165088f6 102 // frontpage course is an exception, on the front page course we should display all users
103 if (empty($rolenames) && $context->id != $frontpagectx->id) {
294a176f 104 if (has_capability('moodle/role:assign', $context)) {
87a13824 105 redirect($CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id);
41d7209c 106 } else {
06e84d52 107 print_error('noparticipants');
41d7209c 108 }
109 }
110
cc038b47 111 add_to_log($course->id, 'user', 'view all', 'index.php?id='.$course->id, '');
f9903ed0 112
77c645df 113 $bulkoperations = has_capability('moodle/course:bulkmessaging', $context);
f1e24e7a 114
68b38e8d 115 $countries = get_list_of_countries();
116
cc038b47 117 $strnever = get_string('never');
68b38e8d 118
a59e5a1c 119 $datestring->year = get_string('year');
120 $datestring->years = get_string('years');
cc038b47 121 $datestring->day = get_string('day');
122 $datestring->days = get_string('days');
123 $datestring->hour = get_string('hour');
124 $datestring->hours = get_string('hours');
125 $datestring->min = get_string('min');
126 $datestring->mins = get_string('mins');
127 $datestring->sec = get_string('sec');
128 $datestring->secs = get_string('secs');
d578afc8 129
ff3caf30 130 if ($mode !== NULL) {
073af1a6 131 $mode = (int)$mode;
132 $SESSION->userindexmode = $mode;
ff3caf30 133 } else if (isset($SESSION->userindexmode)) {
073af1a6 134 $mode = (int)$SESSION->userindexmode;
ff3caf30 135 } else {
073af1a6 136 $mode = MODE_BRIEF;
ff3caf30 137 }
138
4cd0d3a0 139/// Check to see if groups are being used in this course
ff3caf30 140/// and if so, set $currentgroup to reflect the current group
141
ffc536af 142 $groupmode = groups_get_course_groupmode($course); // Groups are being used
143 $currentgroup = groups_get_course_group($course, true);
ff3caf30 144
cc038b47 145 if (!$currentgroup) { // To make some other functions work better later
146 $currentgroup = NULL;
147 }
ff3caf30 148
728a4ebe 149 $isseparategroups = ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context));
2cb2ce61 150
0be6f678 151 if ($isseparategroups and (!$currentgroup) ) {
152 $navlinks = array();
153 $navlinks[] = array('name' => get_string('participants'), 'link' => null, 'type' => 'misc');
154 $navigation = build_navigation($navlinks);
155
156 print_header("$course->shortname: ".get_string('participants'), $course->fullname, $navigation, "", "", true, "&nbsp;", navmenu($course));
4cd0d3a0 157 print_heading(get_string("notingroup"));
ff3caf30 158 print_footer($course);
159 exit;
160 }
161
cc038b47 162 // Should use this variable so that we don't break stuff every time a variable is added or changed.
ffc536af 163 $baseurl = $CFG->wwwroot.'/user/index.php?contextid='.$context->id.'&amp;roleid='.$roleid.'&amp;id='.$course->id.'&amp;perpage='.$perpage.'&amp;accesssince='.$accesssince.'&amp;search='.s($search);
ff3caf30 164
165/// Print headers
2cb2ce61 166
0be6f678 167 $navlinks = array();
168 $navlinks[] = array('name' => get_string('participants'), 'link' => null, 'type' => 'misc');
169 $navigation = build_navigation($navlinks);
1242eb8f 170
0be6f678 171 print_header("$course->shortname: ".get_string('participants'), $course->fullname, $navigation, "", "", true, "&nbsp;", navmenu($course));
b373a751 172
224aa44a 173/// setting up tags
e957cc26 174 if ($course->id == SITEID) {
1242eb8f 175 $filtertype = 'site';
e957cc26 176 } else if ($course->id && !$currentgroup) {
1242eb8f 177 $filtertype = 'course';
e957cc26 178 $filterselect = $course->id;
1242eb8f 179 } else {
180 $filtertype = 'group';
181 $filterselect = $currentgroup;
182 }
183 $currenttab = 'participants';
184 $user = $USER;
1118434a 185 $userindexpage = true;
1242eb8f 186
187 require_once($CFG->dirroot .'/user/tabs.php');
188
189
3468d58a 190/// Get the hidden field list
224aa44a 191 if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
3468d58a 192 $hiddenfields = array(); // teachers and admins are allowed to see everything
193 } else {
194 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
195 }
196
5ff311f0 197 if (isset($hiddenfields['lastaccess'])) {
198 // do not allow access since filtering
199 $accesssince = 0;
200 }
bbbf2d40 201
ff3caf30 202/// Print settings and things in a table across the top
203
cc038b47 204 echo '<table class="controls" cellspacing="0"><tr>';
ff3caf30 205
a72784d3 206/// Print my course menus
7da0af9f 207 if ($mycourses = get_my_courses($USER->id)) {
208 echo '<td class="left">';
7da0af9f 209 $courselist = array();
210 foreach ($mycourses as $mycourse) {
364eef74 211 $courselist[$mycourse->id] = format_string($mycourse->shortname);
7da0af9f 212 }
1118434a 213 if (has_capability('moodle/site:viewparticipants', $systemcontext)) {
5f9e296a 214 unset($courselist[SITEID]);
215 $courselist = array(SITEID => format_string($SITE->shortname)) + $courselist;
216 }
87a13824 217 popup_form($CFG->wwwroot.'/user/index.php?roleid='.$roleid.'&amp;sifirst=&amp;silast=&amp;id=',
224aa44a 218 $courselist, 'courseform', $course->id, '', '', '', false, 'self', get_string('mycourses'));
7da0af9f 219 echo '</td>';
220 }
87a13824 221
9fffb691 222 echo '<td class="left">';
ffc536af 223 groups_print_course_menu($course, $baseurl);
9fffb691 224 echo '</td>';
ff3caf30 225
5ff311f0 226 if (!isset($hiddenfields['lastaccess'])) {
227 // get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far.
228 // we need to make it diferently for normal courses and site course
229 if ($context->id != $frontpagectx->id) {
230 $minlastaccess = $DB->get_field_sql('SELECT min(timeaccess)
231 FROM {user_lastaccess}
232 WHERE courseid = ?
233 AND timeaccess != 0', array($course->id));
234 $lastaccess0exists = $DB->record_exists('user_lastaccess', array('courseid'=>$course->id, 'timeaccess'=>0));
235 } else {
236 $minlastaccess = $DB->get_field_sql('SELECT min(lastaccess)
237 FROM {user}
238 WHERE lastaccess != 0');
239 $lastaccess0exists = $DB->record_exists('user', array('lastaccess'=>0));
240 }
0749caef 241
5ff311f0 242 $now = usergetmidnight(time());
243 $timeaccess = array();
87a13824 244
5ff311f0 245 // makes sense for this to go first.
246 $timeoptions[0] = get_string('selectperiod');
87a13824 247
5ff311f0 248 // days
249 for ($i = 1; $i < 7; $i++) {
250 if (strtotime('-'.$i.' days',$now) >= $minlastaccess) {
251 $timeoptions[strtotime('-'.$i.' days',$now)] = get_string('numdays','moodle',$i);
252 }
ca792680 253 }
5ff311f0 254 // weeks
255 for ($i = 1; $i < 10; $i++) {
256 if (strtotime('-'.$i.' weeks',$now) >= $minlastaccess) {
257 $timeoptions[strtotime('-'.$i.' weeks',$now)] = get_string('numweeks','moodle',$i);
258 }
ca792680 259 }
5ff311f0 260 // months
261 for ($i = 2; $i < 12; $i++) {
262 if (strtotime('-'.$i.' months',$now) >= $minlastaccess) {
263 $timeoptions[strtotime('-'.$i.' months',$now)] = get_string('nummonths','moodle',$i);
264 }
265 }
266 // try a year
267 if (strtotime('-1 year',$now) >= $minlastaccess) {
268 $timeoptions[strtotime('-1 year',$now)] = get_string('lastyear');
31b71336 269 }
87a13824 270
5ff311f0 271 if (!empty($lastaccess0exists)) {
272 $timeoptions[-1] = get_string('never');
273 }
87a13824 274
5ff311f0 275 if (count($timeoptions) > 1) {
276 echo '<td class="left">';
277 $baseurl = preg_replace('/&amp;accesssince='.$accesssince.'/','',$baseurl);
278 popup_form($baseurl.'&amp;accesssince=',$timeoptions,'timeoptions',$accesssince, '', '', '', false, 'self', get_string('usersnoaccesssince'));
279 echo '</td>';
280 }
77c645df 281 }
87a13824 282
073af1a6 283 // Decide wheteher we will fetch extra enrolment/groups data.
284 //
285 // MODE_ENROLDETAILS is expensive, and only suitable where the listing is small
286 // (at or below DEFAULT_PAGE_SIZE) and $USER can enrol/unenrol
287 // (will take 1 extra DB query - 2 on Oracle)
288 //
06e84d52 289 if ($course->id != SITEID && $perpage <= DEFAULT_PAGE_SIZE
073af1a6 290 && has_capability('moodle/role:assign',$context)) {
291 $allowenroldetails=true;
292 } else {
293 $allowenroldetails=false;
294 }
295 if ($mode === MODE_ENROLDETAILS && !($allowenroldetails)) {
296 // conditions haven't been met - reset
297 $mode = MODE_BRIEF;
298 }
31b71336 299
cc038b47 300 echo '<td class="right">';
073af1a6 301 $formatmenu = array( '0' => get_string('brief'),
302 '1' => get_string('userdetails'));
303 if ($allowenroldetails) {
304 $formatmenu['2']= get_string('enroldetails');
305 }
306 popup_form($baseurl.'&amp;mode=', $formatmenu, 'formatmenu', $mode, '', '', '', false, 'self', get_string('userlist'));
ff3caf30 307 echo '</td></tr></table>';
308
224aa44a 309 if ($currentgroup and (!$isseparategroups or has_capability('moodle/site:accessallgroups', $context))) { /// Display info about the group
ffc536af 310 if ($group = groups_get_group($currentgroup)) {
87a13824 311 if (!empty($group->description) or (!empty($group->picture) and empty($group->hidepicture))) {
ff3caf30 312 echo '<table class="groupinfobox"><tr><td class="left side picture">';
313 print_group_picture($group, $course->id, true, false, false);
314 echo '</td><td class="content">';
315 echo '<h3>'.$group->name;
224aa44a 316 if (has_capability('moodle/course:managegroups', $context)) {
c4e953e6 317 echo '&nbsp;<a title="'.get_string('editgroupprofile').'" href="'.$CFG->wwwroot.'/group/group.php?id='.$group->id.'&amp;courseid='.$group->courseid.'">';
f2a1963c 318 echo '<img src="'.$OUTPUT->old_icon_url('t/edit') . '" alt="'.get_string('editgroupprofile').'" />';
2c27cd19 319 echo '</a>';
320 }
ff3caf30 321 echo '</h3>';
322 echo format_text($group->description);
323 echo '</td></tr></table>';
324 }
325 }
326 }
327
77c645df 328 /// Define a table showing a list of users in the current role selection
329
1d40c70b 330 $tablecolumns = array('userpic', 'fullname');
d6cc2341 331 $tableheaders = array(get_string('userpic'), get_string('fullnameuser'));
073af1a6 332 if ($mode === MODE_BRIEF && !isset($hiddenfields['city'])) {
77c645df 333 $tablecolumns[] = 'city';
334 $tableheaders[] = get_string('city');
335 }
073af1a6 336 if ($mode === MODE_BRIEF && !isset($hiddenfields['country'])) {
77c645df 337 $tablecolumns[] = 'country';
338 $tableheaders[] = get_string('country');
339 }
340 if (!isset($hiddenfields['lastaccess'])) {
341 $tablecolumns[] = 'lastaccess';
342 $tableheaders[] = get_string('lastaccess');
343 }
344
345 if ($course->enrolperiod) {
346 $tablecolumns[] = 'timeend';
347 $tableheaders[] = get_string('enrolmentend');
348 }
349
073af1a6 350 if ($mode === MODE_ENROLDETAILS) {
664fe87f 351 $tablecolumns[] = 'roles';
352 $tableheaders[] = get_string('roles');
a32e05df 353 if ($groupmode != 0) {
354 $tablecolumns[] = 'groups';
355 $tableheaders[] = get_string('groups');
356 if (!empty($CFG->enablegroupings)) {
357 $tablecolumns[] = 'groupings';
358 $tableheaders[] = get_string('groupings', 'group');
359 }
664fe87f 360 }
361 }
362
77c645df 363 if ($bulkoperations) {
664fe87f 364 $tablecolumns[] = 'select';
77c645df 365 $tableheaders[] = get_string('select');
366 }
367
04186cd9 368 $table = new flexible_table('user-index-participants-'.$course->id);
77c645df 369
370 $table->define_columns($tablecolumns);
371 $table->define_headers($tableheaders);
372 $table->define_baseurl($baseurl);
0be6f678 373
5ff311f0 374 if (!isset($hiddenfields['lastaccess'])) {
375 $table->sortable(true, 'lastaccess', SORT_DESC);
376 }
377
664fe87f 378 $table->no_sorting('roles');
379 $table->no_sorting('groups');
380 $table->no_sorting('groupings');
381 $table->no_sorting('select');
77c645df 382
383 $table->set_attribute('cellspacing', '0');
04186cd9 384 $table->set_attribute('id', 'participants');
77c645df 385 $table->set_attribute('class', 'generaltable generalbox');
386
387 $table->set_control_variables(array(
388 TABLE_VAR_SORT => 'ssort',
389 TABLE_VAR_HIDE => 'shide',
390 TABLE_VAR_SHOW => 'sshow',
391 TABLE_VAR_IFIRST => 'sifirst',
392 TABLE_VAR_ILAST => 'silast',
393 TABLE_VAR_PAGE => 'spage'
394 ));
395 $table->setup();
396
ce8c75ee 397 $params = array();
77c645df 398 // we are looking for all users with this role assigned in this context or higher
399 if ($usercontexts = get_parent_contexts($context)) {
400 $listofcontexts = '('.implode(',', $usercontexts).')';
401 } else {
1118434a 402 $listofcontexts = '('.$systemcontext->id.')'; // must be site
77c645df 403 }
5f9e296a 404 if ($roleid > 0) {
ce8c75ee 405 $selectrole = " AND r.roleid = :roleid ";
406 $params['roleid'] = $roleid;
77c645df 407 } else {
408 $selectrole = " ";
409 }
5f9e296a 410
165088f6 411 if ($context->id != $frontpagectx->id) {
5f2a203f 412 $select = 'SELECT DISTINCT u.id, u.username, u.firstname, u.lastname,
b6ac3623 413 u.email, u.city, u.country, u.picture,
414 u.lang, u.timezone, u.emailstop, u.maildisplay, u.imagealt,
415 COALESCE(ul.timeaccess, 0) AS lastaccess,
416 r.hidden,
417 ctx.id AS ctxid, ctx.path AS ctxpath,
5f9e296a 418 ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel ';
165088f6 419 $select .= $course->enrolperiod?', r.timeend ':'';
420 } else {
5f9e296a 421 if ($roleid >= 0) {
422 $select = 'SELECT u.id, u.username, u.firstname, u.lastname,
423 u.email, u.city, u.country, u.picture,
424 u.lang, u.timezone, u.emailstop, u.maildisplay, u.imagealt,
425 u.lastaccess, r.hidden,
426 ctx.id AS ctxid, ctx.path AS ctxpath,
427 ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel ';
428 } else {
429 $select = 'SELECT u.id, u.username, u.firstname, u.lastname,
430 u.email, u.city, u.country, u.picture,
431 u.lang, u.timezone, u.emailstop, u.maildisplay, u.imagealt,
432 u.lastaccess,
433 ctx.id AS ctxid, ctx.path AS ctxpath,
434 ctx.depth AS ctxdepth, ctx.contextlevel AS ctxlevel ';
435 }
165088f6 436 }
b6ac3623 437
5f9e296a 438 if ($context->id != $frontpagectx->id or $roleid >= 0) {
ce8c75ee 439 $from = "FROM {user} u
440 LEFT OUTER JOIN {context} ctx
441 ON (u.id=ctx.instanceid AND ctx.contextlevel = ".CONTEXT_USER.")
442 JOIN {role_assignments} r
443 ON u.id=r.userid
444 LEFT OUTER JOIN {user_lastaccess} ul
445 ON (r.userid=ul.userid and ul.courseid = :courseid) ";
446 $params['courseid'] = $course->id;
165088f6 447 } else {
5f9e296a 448 // on frontpage and we want all registered users
ce8c75ee 449 $from = "FROM {user} u
450 LEFT OUTER JOIN {context} ctx
451 ON (u.id=ctx.instanceid AND ctx.contextlevel = ".CONTEXT_USER.") ";
165088f6 452 }
5f9e296a 453
0be6f678 454 $hiddensql = has_capability('moodle/role:viewhiddenassigns', $context)? '':' AND r.hidden = 0 ';
c0527567 455
b373a751 456 // exclude users with roles we are avoiding
457 if ($avoidroles) {
789154a6 458 $adminroles = 'AND r.roleid NOT IN (';
b373a751 459 $adminroles .= implode(',', $avoidroles);
c0527567 460 $adminroles .= ')';
461 } else {
462 $adminroles = '';
463 }
0be6f678 464
1e248b44 465 // join on 2 conditions
466 // otherwise we run into the problem of having records in ul table, but not relevant course
467 // and user record is not pulled out
5f9e296a 468
165088f6 469 if ($context->id != $frontpagectx->id) {
470 $where = "WHERE (r.contextid = $context->id OR r.contextid in $listofcontexts)
ce8c75ee 471 AND u.deleted = 0 $selectrole
472 AND (ul.courseid = $course->id OR ul.courseid IS NULL)
473 AND u.username != 'guest'
474 $adminroles
475 $hiddensql ";
0749caef 476 $where .= get_course_lastaccess_sql($accesssince);
165088f6 477 } else {
5f9e296a 478 if ($roleid >= 0) {
479 $where = "WHERE (r.contextid = $context->id OR r.contextid in $listofcontexts)
ce8c75ee 480 AND u.deleted = 0 $selectrole
481 AND u.username != 'guest'";
482 $where .= get_user_lastaccess_sql($accesssince);
5f9e296a 483 } else {
484 $where = "WHERE u.deleted = 0
485 AND u.username != 'guest'";
486 $where .= get_user_lastaccess_sql($accesssince);
487 }
165088f6 488 }
77c645df 489 $wheresearch = '';
490
491 if (!empty($search)) {
ce8c75ee 492 $LIKE = $DB->sql_ilike();
493 $fullname = $DB->sql_fullname('u.firstname','u.lastname');
494 $wheresearch .= " AND ($fullname $LIKE :search1 OR email $LIKE :search2 OR idnumber $LIKE :search3) ";
495 $params['search1'] = "%$search%";
496 $params['search2'] = "%$search%";
497 $params['search3'] = "%$search%";
77c645df 498 }
499
500 if ($currentgroup) { // Displaying a group by choice
501 // FIX: TODO: This will not work if $currentgroup == 0, i.e. "those not in a group"
ce8c75ee 502 $from .= 'LEFT JOIN {groups_members} gm ON u.id = gm.userid ';
503 $where .= ' AND gm.groupid = :currentgroup';
d559bdc0 504 $params['currentgroup'] = $currentgroup;
77c645df 505 }
506
ce8c75ee 507 $totalcount = $DB->count_records_sql("SELECT COUNT(distinct u.id) $from $where", $params); // Each user could have > 1 role
77c645df 508
509 if ($table->get_sql_where()) {
510 $where .= ' AND '.$table->get_sql_where();
511 }
512
1f807bc4 513 /// Always add r.hidden to sort in order to guarantee hiddens to "win"
514 /// in the resolution of duplicates later - MDL-13935
4d93bc9e 515 /// Only exception is frontpage that doesn't have such r.hidden info
516 /// because it retrieves ALL users (without role checking) - MDL-14034
77c645df 517 if ($table->get_sql_sort()) {
4d93bc9e 518 $sort = ' ORDER BY '.$table->get_sql_sort();
5f9e296a 519 if ($context->id != $frontpagectx->id or $roleid >= 0) {
4d93bc9e 520 $sort .= ', r.hidden DESC';
521 }
77c645df 522 } else {
4d93bc9e 523 $sort = '';
5f9e296a 524 if ($context->id != $frontpagectx->id or $roleid >= 0) {
4d93bc9e 525 $sort .= ' ORDER BY r.hidden DESC';
526 }
77c645df 527 }
528
ce8c75ee 529 $matchcount = $DB->count_records_sql("SELECT COUNT(distinct u.id) $from $where $wheresearch", $params);
77c645df 530
281917e9 531 $table->initialbars(true);
77c645df 532 $table->pagesize($perpage, $matchcount);
533
ce8c75ee 534 $userlist = $DB->get_recordset_sql("$select $from $where $wheresearch $sort", $params,
77c645df 535 $table->get_page_start(), $table->get_page_size());
3e219038 536
664fe87f 537 //
538 // The SELECT behind get_participants_extra() is cheaper if we pass an array
539 // if IDs. We could pass the SELECT we did before (with the limit bits - tricky!)
540 // but this is much cheaper. And in any case, it is only doable with limited numbers
541 // of rows anyway. On a large course it will explode badly...
542 //
073af1a6 543 if ($mode===MODE_ENROLDETAILS) {
5f772e4a 544 if ($context->id != $frontpagectx->id) {
545 $userids = $DB->get_fieldset_sql("SELECT DISTINCT u.id $from $where $wheresearch", $params,
546 $table->get_page_start(), $table->get_page_size());
547 } else {
548 $userids = $DB->get_fieldset_sql("SELECT u.id $from $where $wheresearch", $params,
549 $table->get_page_start(), $table->get_page_size());
550 }
664fe87f 551 $userlist_extra = get_participants_extra($userids, $avoidroles, $course, $context);
664fe87f 552 }
553
5f9e296a 554 if ($context->id == $frontpagectx->id) {
555 $strallsiteusers = get_string('allsiteusers', 'role');
556 if ($CFG->defaultfrontpageroleid) {
ce8c75ee 557 if ($fprole = $DB->get_record('role', array('id'=>$CFG->defaultfrontpageroleid))) {
5f9e296a 558 $fprole = role_get_name($fprole, $frontpagectx);
559 $strallsiteusers = "$strallsiteusers ($fprole)";
560 }
561 }
562 $rolenames = array(-1 => $strallsiteusers) + $rolenames;
563 }
3e219038 564
5f9e296a 565 /// If there are multiple Roles in the course, then show a drop down menu for switching
6d3c57f4 566 if (count($rolenames) > 1) {
77c645df 567 echo '<div class="rolesform">';
5f9e296a 568 echo '<label for="rolesform_jump">'.get_string('currentrole', 'role').'&nbsp;</label>';
569 if ($context->id != $frontpagectx->id) {
570 $rolenames = array(0 => get_string('all')) + $rolenames;
571 } else {
572 if (!$CFG->defaultfrontpageroleid) {
573 // we do not want "All users with role" - we already have all users in defualt frontpage role option
574 $rolenames = array(0 => get_string('userswithrole', 'role')) + $rolenames;
575 }
576 }
6d3c57f4 577 popup_form("$CFG->wwwroot/user/index.php?contextid=$context->id&amp;sifirst=&amp;silast=&amp;roleid=", $rolenames,
77c645df 578 'rolesform', $roleid, '');
0f870a49 579 echo '</div>';
5f9e296a 580
581 } else if (count($rolenames) == 1) {
582 // when all users with the same role - print its name
583 echo '<div class="rolesform">';
584 echo get_string('role').': ';
585 $rolename = reset($rolenames);
586 echo $rolename;
587 echo '</div>';
77c645df 588 }
3e219038 589
5f9e296a 590 if ($roleid > 0) {
ce8c75ee 591 if (!$currentrole = $DB->get_record('role', array('id'=>$roleid))) {
06e84d52 592 print_error('invalidroleid');
e957cc26 593 }
b90e2f19 594 $a->number = $totalcount;
ed61510b 595 // MDL-12217, use course specific rolename
596 if (isset($rolenames[$currentrole->id])){
597 $a->role = $rolenames[$currentrole->id];
5f9e296a 598 }else{
ed61510b 599 $a->role = $currentrole->name;//safety net
600 }
5f9e296a 601 $heading = format_string(get_string('xuserswiththerole', 'role', $a));
f642a21a 602
603 if ($currentgroup and $group) {
604 $a->group = $group->name;
5f9e296a 605 $heading .= ' ' . format_string(get_string('ingroup', 'role', $a));
606 }
f642a21a 607
608 if ($accesssince) {
609 $a->timeperiod = $timeoptions[$accesssince];
5f9e296a 610 $heading .= ' ' . format_string(get_string('inactiveformorethan', 'role', $a));
f642a21a 611 }
612
613 $heading .= ": $a->number";
d02eeded 614 if (user_can_assign($context, $roleid)) {
3e219038 615 $heading .= ' <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?roleid='.$roleid.'&amp;contextid='.$context->id.'">';
f2a1963c 616 $heading .= '<img src="'.$OUTPUT->old_icon_url('i/edit') . '" class="icon" alt="" /></a>';
3e219038 617 }
618 print_heading($heading, 'center', 3);
3e219038 619 } else {
5f9e296a 620 if ($course->id != SITEID && has_capability('moodle/role:assign', $context)) {
15234a92 621 $editlink = ' <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id.'">';
f2a1963c 622 $editlink .= '<img src="'.$OUTPUT->old_icon_url('i/edit') . '" class="icon" alt="" /></a>';
15234a92 623 } else {
624 $editlink = '';
625 }
5f9e296a 626 if ($course->id == SITEID and $roleid < 0) {
627 $strallparticipants = get_string('allsiteusers', 'role');
628 } else {
629 $strallparticipants = get_string('allparticipants');
630 }
23f5ee25 631 if ($matchcount < $totalcount) {
5f9e296a 632 print_heading($strallparticipants.': '.$matchcount.'/'.$totalcount . $editlink, '', 3);
23f5ee25 633 } else {
5f9e296a 634 print_heading($strallparticipants.': '.$matchcount . $editlink, '', 3);
23f5ee25 635 }
3e219038 636 }
3e219038 637
77c645df 638
639 if ($bulkoperations) {
25a2bfda 640 $PAGE->requires->js('user/user.js');
c1138797 641 echo '<form action="action_redir.php" method="post" id="participantsform" onsubmit="return checksubmit(this);">';
642 echo '<div>';
d4a1fcaf 643 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
838c7d29 644 echo '<input type="hidden" name="returnto" value="'.s(me()).'" />';
77c645df 645 }
646
647 if ($CFG->longtimenosee > 0 && $CFG->longtimenosee < 1000 && $totalcount > 0) {
648 echo '<p id="longtimenosee">('.get_string('unusedaccounts', '', $CFG->longtimenosee).')</p>';
649 }
650
073af1a6 651 if ($mode===MODE_USERDETAILS) { // Print simple listing
77c645df 652 if ($totalcount < 1) {
04186cd9 653 print_heading(get_string('nothingtodisplay'));
77c645df 654 } else {
655 if ($totalcount > $perpage) {
656
657 $firstinitial = $table->get_initial_first();
658 $lastinitial = $table->get_initial_last();
659 $strall = get_string('all');
660 $alpha = explode(',', get_string('alphabet'));
661
662 // Bar of first initials
663
664 echo '<div class="initialbar firstinitial">'.get_string('firstname').' : ';
665 if(!empty($firstinitial)) {
666 echo '<a href="'.$baseurl.'&amp;sifirst=">'.$strall.'</a>';
667 } else {
668 echo '<strong>'.$strall.'</strong>';
669 }
670 foreach ($alpha as $letter) {
671 if ($letter == $firstinitial) {
672 echo ' <strong>'.$letter.'</strong>';
ee4a52c5 673 } else {
77c645df 674 echo ' <a href="'.$baseurl.'&amp;sifirst='.$letter.'">'.$letter.'</a>';
ee4a52c5 675 }
ee4a52c5 676 }
77c645df 677 echo '</div>';
678
679 // Bar of last initials
680
681 echo '<div class="initialbar lastinitial">'.get_string('lastname').' : ';
682 if(!empty($lastinitial)) {
683 echo '<a href="'.$baseurl.'&amp;silast=">'.$strall.'</a>';
684 } else {
685 echo '<strong>'.$strall.'</strong>';
686 }
687 foreach ($alpha as $letter) {
688 if ($letter == $lastinitial) {
689 echo ' <strong>'.$letter.'</strong>';
690 } else {
691 echo ' <a href="'.$baseurl.'&amp;silast='.$letter.'">'.$letter.'</a>';
ee4a52c5 692 }
693 }
77c645df 694 echo '</div>';
695
696 print_paging_bar($matchcount, intval($table->get_page_start() / $perpage), $perpage, $baseurl.'&amp;', 'spage');
697 }
698
699 if ($matchcount > 0) {
1f807bc4 700 $usersprinted = array();
ce8c75ee 701 foreach ($userlist as $user) {
1f807bc4 702 if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935
703 continue;
704 }
705 $usersprinted[] = $user->id; /// Add new user to the array of users printed
706
b6ac3623 707 $user = make_context_subobj($user);
04186cd9 708 print_user($user, $course, $bulkoperations);
ee4a52c5 709 }
77c645df 710
711 } else {
712 print_heading(get_string('nothingtodisplay'));
ee4a52c5 713 }
714 }
77c645df 715
716 } else {
717 $countrysort = (strpos($sort, 'country') !== false);
718 $timeformat = get_string('strftimedate');
3997cb40 719
720
03cedd62 721 if ($userlist) {
664fe87f 722
723 // only show the plugin if multiple enrolment plugins
724 // are enabled...
725 if (strpos($CFG->enrol_plugins_enabled, ',')=== false) {
726 $showenrolplugin = true;
727 } else {
728 $showenrolplugin = false;
729 }
1f807bc4 730
731 $usersprinted = array();
ce8c75ee 732 foreach ($userlist as $user) {
1f807bc4 733 if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935
734 continue;
735 }
736 $usersprinted[] = $user->id; /// Add new user to the array of users printed
737
b6ac3623 738 $user = make_context_subobj($user);
13d1f5a6 739 if ( !empty($user->hidden) ) {
3997cb40 740 // if the assignment is hidden, display icon
ddedf979 741 $hidden = " <img src=\"" . $OUTPUT->old_icon_url('t/show') . "\" title=\"".get_string('userhashiddenassignments', 'role')."\" alt=\"".get_string('hiddenassign')."\" class=\"hide-show-image\"/>";
3997cb40 742 } else {
0be6f678 743 $hidden = '';
3997cb40 744 }
0be6f678 745
04186cd9 746 if ($user->lastaccess) {
747 $lastaccess = format_time(time() - $user->lastaccess, $datestring);
77c645df 748 } else {
749 $lastaccess = $strnever;
750 }
751
04186cd9 752 if (empty($user->country)) {
77c645df 753 $country = '';
754
755 } else {
756 if($countrysort) {
04186cd9 757 $country = '('.$user->country.') '.$countries[$user->country];
ee4a52c5 758 }
759 else {
04186cd9 760 $country = $countries[$user->country];
ee4a52c5 761 }
77c645df 762 }
0be6f678 763
b6ac3623 764 if (!isset($user->context)) {
765 $usercontext = get_context_instance(CONTEXT_USER, $user->id);
766 } else {
767 $usercontext = $user->context;
768 }
0be6f678 769
b08261a1 770 if ($piclink = ($USER->id == $user->id || has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext))) {
22ae509e 771 $profilelink = '<strong><a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.fullname($user).'</a></strong>';
772 } else {
0be6f678 773 $profilelink = '<strong>'.fullname($user).'</strong>';
22ae509e 774 }
0be6f678 775
77c645df 776 $data = array (
a5d81e5e 777 print_user_picture($user, $course->id, $user->picture, false, true, $piclink),
13d1f5a6 778 $profilelink . $hidden);
22ae509e 779
073af1a6 780 if ($mode === MODE_BRIEF && !isset($hiddenfields['city'])) {
04186cd9 781 $data[] = $user->city;
77c645df 782 }
073af1a6 783 if ($mode === MODE_BRIEF && !isset($hiddenfields['country'])) {
77c645df 784 $data[] = $country;
785 }
786 if (!isset($hiddenfields['lastaccess'])) {
787 $data[] = $lastaccess;
788 }
789 if ($course->enrolperiod) {
04186cd9 790 if ($user->timeend) {
791 $data[] = userdate($user->timeend, $timeformat);
77c645df 792 } else {
793 $data[] = get_string('unlimited');
ee4a52c5 794 }
ee4a52c5 795 }
664fe87f 796
797 if (isset($userlist_extra) && isset($userlist_extra[$user->id])) {
798 $ras = $userlist_extra[$user->id]['ra'];
799 $rastring = '';
800 foreach ($ras AS $key=>$ra) {
801 $rolename = $rolenames [ $ra['roleid'] ] ;
802 if ($ra['ctxlevel'] == CONTEXT_COURSECAT) {
073af1a6 803 $rastring .= $rolename. ' @ ' . '<a href="'.$CFG->wwwroot.'/course/category.php?id='.$ra['ctxinstanceid'].'">'.s($ra['ccname']).'</a>';
664fe87f 804 } elseif ($ra['ctxlevel'] == CONTEXT_SYSTEM) {
073af1a6 805 $rastring .= $rolename. ' - ' . get_string('globalrole','role');
664fe87f 806 } else {
807 $rastring .= $rolename;
808 }
809 if ($showenrolplugin) {
810 $rastring .= '<br />';
811 } else {
812 $rastring .= ' ('. $ra['enrolplugin'] .')<br />';
813 }
814 }
06e84d52 815 $data[] = $rastring;
a32e05df 816 if ($groupmode != 0) {
664fe87f 817 // htmlescape with s() and implode the array
818 $data[] = implode(', ', array_map('s',$userlist_extra[$user->id]['group']));
a32e05df 819 if (!empty($CFG->enablegroupings)) {
820 $data[] = implode(', ', array_map('s', $userlist_extra[$user->id]['gping']));
821 }
664fe87f 822 }
664fe87f 823 }
824
77c645df 825 if ($bulkoperations) {
04186cd9 826 $data[] = '<input type="checkbox" name="user'.$user->id.'" />';
77c645df 827 }
828 $table->add_data($data);
ee4a52c5 829
ee4a52c5 830 }
ee4a52c5 831 }
b90e2f19 832
77c645df 833 $table->print_html();
834
835 }
836
837 if ($bulkoperations) {
c1138797 838 echo '<br /><div class="buttons">';
77c645df 839 echo '<input type="button" onclick="checkall()" value="'.get_string('selectall').'" /> ';
840 echo '<input type="button" onclick="checknone()" value="'.get_string('deselectall').'" /> ';
82d561ee 841 $displaylist = array();
576ad290 842 $displaylist['messageselect.php'] = get_string('messageselectadd');
90658eef 843 if (!empty($CFG->enablenotes) && has_capability('moodle/notes:manage', $context) && $context->id != $frontpagectx->id) {
eca3af25 844 $displaylist['addnote.php'] = get_string('addnewnote', 'notes');
845 $displaylist['groupaddnote.php'] = get_string('groupaddnewnote', 'notes');
846 }
576ad290 847
165088f6 848 if ($context->id != $frontpagectx->id) {
849 $displaylist['extendenrol.php'] = get_string('extendenrol');
850 $displaylist['groupextendenrol.php'] = get_string('groupextendenrol');
851 }
0be6f678 852
77c645df 853 helpbutton("participantswithselectedusers", get_string("withselectedusers"));
49c8c8d2 854 $select = new moodle_select();
855 $select->options = $displaylist;
856 $select->name = "formaction";
857 $select->label = get_string("withselectedusers");
858 $select->add_action('change', 'conditionalsubmit', array('formid' => 'participantsform'));
859 echo $OUTPUT->select($select);
70ce923e 860 echo '<input type="hidden" name="id" value="'.$course->id.'" />';
cab6762b 861 echo '<div id="noscriptparticipantsform" style="display: inline;">';
862 echo '<input type="submit" value="'.get_string('ok').'" /></div>';
25a2bfda 863 $PAGE->requires->js_function_call('hide_item', Array('noscriptparticipantsform'));
c1138797 864 echo '</div>';
865 echo '</div>';
866 echo '</form>';
d88c5043 867
77c645df 868 }
b90e2f19 869
77c645df 870 if ($bulkoperations && $totalcount > ($perpage*3)) {
8c275093 871 echo '<form action="index.php" class="searchform"><div><input type="hidden" name="id" value="'.$course->id.'" />'.get_string('search').':&nbsp;'."\n";
3593af19 872 echo '<input type="text" name="search" value="'.s($search).'" />&nbsp;<input type="submit" value="'.get_string('search').'" /></div></form>'."\n";
77c645df 873 }
b90e2f19 874
a2c4671e 875 $perpageurl = preg_replace('/&amp;perpage=\d*/','', $baseurl);
77c645df 876 if ($perpage == SHOW_ALL_PAGE_SIZE) {
a2c4671e 877 echo '<div id="showall"><a href="'.$perpageurl.'&amp;perpage='.DEFAULT_PAGE_SIZE.'">'.get_string('showperpage', '', DEFAULT_PAGE_SIZE).'</a></div>';
77c645df 878
879 } else if ($matchcount > 0 && $perpage < $matchcount) {
a2c4671e 880 echo '<div id="showall"><a href="'.$perpageurl.'&amp;perpage='.SHOW_ALL_PAGE_SIZE.'">'.get_string('showall', '', $matchcount).'</a></div>';
b90e2f19 881 }
77c645df 882
cc038b47 883 print_footer($course);
f9903ed0 884
03cedd62 885 if ($userlist) {
ce8c75ee 886 $userlist->close();
03cedd62 887 }
77c645df 888
889
0749caef 890function get_course_lastaccess_sql($accesssince='') {
31b71336 891 if (empty($accesssince)) {
892 return '';
893 }
894 if ($accesssince == -1) { // never
dfe60358 895 return ' AND ul.timeaccess = 0';
31b71336 896 } else {
0749caef 897 return ' AND ul.timeaccess != 0 AND ul.timeaccess < '.$accesssince;
898 }
899}
900
901function get_user_lastaccess_sql($accesssince='') {
902 if (empty($accesssince)) {
903 return '';
904 }
905 if ($accesssince == -1) { // never
906 return ' AND u.lastaccess = 0';
907 } else {
908 return ' AND u.lastaccess != 0 AND u.lastaccess < '.$accesssince;
31b71336 909 }
910}
911
664fe87f 912function get_participants_extra ($userids, $avoidroles, $course, $context) {
ce8c75ee 913 global $CFG, $DB;
664fe87f 914
915 if (count($userids) === 0 || count($avoidroles) === 0) {
916 return array();
917 }
918
ce8c75ee 919 $params = array();
920
664fe87f 921 $userids = implode(',', $userids);
922
923 // turn the path into a list of context ids
924 $contextids = substr($context->path, 1); // kill leading slash
925 $contextids = str_replace('/', ',', $contextids);;
926
927 if (count($avoidroles) > 0) {
928 $avoidroles = implode(',', $avoidroles);
929 $avoidrolescond = " AND ra.roleid NOT IN ($avoidroles) ";
930 } else {
931 $avoidrolescond = '';
932 }
933
934 if (!empty($CFG->enablegroupings)) {
ce8c75ee 935 $gpjoin = "LEFT OUTER JOIN {groupings_groups} gpg
936 ON gpg.groupid=g.id
937 LEFT OUTER JOIN {groupings} gp
938 ON (gp.courseid={$course->id} AND gp.id=gpg.groupingid)";
664fe87f 939 $gpselect = ',gp.id AS gpid, gp.name AS gpname ';
940 } else {
941 $gpjoin = '';
942 $gpselect = '';
943 }
944
945 // Note: this returns strange redundant rows, perhaps
946 // due to the multiple OUTER JOINs. If we can tweak the
947 // JOINs to avoid it ot
06e84d52 948 $sql = "SELECT DISTINCT ra.userid,
949 ctx.id AS ctxid, ctx.path AS ctxpath, ctx.depth AS ctxdepth,
664fe87f 950 ctx.contextlevel AS ctxlevel, ctx.instanceid AS ctxinstanceid,
06e84d52 951 cc.name AS ccname,
664fe87f 952 ra.roleid AS roleid,
953 ra.enrol AS enrolplugin,
954 g.id AS gid, g.name AS gname
955 $gpselect
ce8c75ee 956 FROM {role_assignments} ra
957 JOIN {context} ctx
958 ON (ra.contextid=ctx.id)
959 LEFT JOIN {course_categories} cc
960 ON (ctx.contextlevel=40 AND ctx.instanceid=cc.id)
664fe87f 961
962 /* only if groups active */
ce8c75ee 963 LEFT JOIN {groups_members} gm
964 ON (ra.userid=gm.userid)
965 LEFT JOIN {groups} g
966 ON (gm.groupid=g.id AND g.courseid={$course->id})
664fe87f 967 /* and if groupings is enabled... */
968 $gpjoin
969
06e84d52 970 WHERE ra.userid IN ( $userids )
971 AND ra.contextid in ( $contextids )
ce8c75ee 972 $avoidrolescond
664fe87f 973
ce8c75ee 974 ORDER BY ra.userid, ctx.depth DESC";
664fe87f 975
ce8c75ee 976 $rs = $DB->get_recordset_sql($sql, $params);
664fe87f 977 $extra = array();
978
979 // Data structure -
980 // $extra [ $userid ] [ 'group' ] [ $groupid => 'group name']
981 // [ 'gping' ] [ $gpingid => 'gping name']
982 // [ 'ra' ] [ [ "$ctxid:$roleid" => [ctxid => $ctxid
06e84d52 983 // ctxdepth => $ctxdepth,
664fe87f 984 // ctxpath => $ctxpath,
985 // ctxname => 'name' (categories only)
06e84d52 986 // ctxinstid =>
664fe87f 987 // roleid => $roleid
988 // enrol => $pluginname
989 //
990 // Might be interesting to add to RA timestart, timeend, timemodified,
991 // and modifierid (with an outer join to mdl_user!
992 //
993
ce8c75ee 994 foreach ($rs as $rec) {
664fe87f 995 $userid = $rec->userid;
996
997 // Prime an initial user rec...
998 if (!isset($extra[$userid])) {
999 $extra[$userid] = array( 'group' => array(),
1000 'gping' => array(),
1001 'ra' => array() );
1002 }
1003
1004 if (!empty($rec->gid)) {
1005 $extra[$userid]['group'][$rec->gid]= $rec->gname;
1006 }
1007 if (!empty($rec->gpid)) {
1008 $extra[$userid]['gping'][$rec->gpid]= $rec->gpname;
1009 }
1010 $rakey = $rec->ctxid . ':' . $rec->roleid;
1011 if (!isset($extra[$userid]['ra'][$rakey])) {
1012 $extra[$userid]['ra'][$rakey] = array('ctxid' => $rec->ctxid,
1013 'ctxlevel' => $rec->ctxlevel,
1014 'ctxinstanceid' => $rec->ctxinstanceid,
1015 'ccname' => $rec->ccname,
1016 'roleid' => $rec->roleid,
1017 'enrolplugin' => $rec->enrolplugin);
1018
1019 }
1020 }
ce8c75ee 1021 $rs->close();
664fe87f 1022 return $extra;
1023
1024}
1025
f9903ed0 1026?>