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