MDL-21695 adding help and link strings
[moodle.git] / user / index.php
blobbe216205123568df16822320544b79c0d40ea950
1 <?php
3 // Lists all the users within a given course
5 require_once('../config.php');
6 require_once($CFG->libdir.'/tablelib.php');
8 define('USER_SMALL_CLASS', 20); // Below this is considered small
9 define('USER_LARGE_CLASS', 200); // Above this is considered large
10 define('DEFAULT_PAGE_SIZE', 20);
11 define('SHOW_ALL_PAGE_SIZE', 5000);
12 define('MODE_BRIEF', 0);
13 define('MODE_USERDETAILS', 1);
14 define('MODE_ENROLDETAILS', 2);
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
18 $mode = optional_param('mode', NULL); // use the MODE_ constants
19 $accesssince = optional_param('accesssince',0,PARAM_INT); // filter by last access. -1 = never
20 $search = optional_param('search','',PARAM_CLEAN);
21 $roleid = optional_param('roleid', 0, PARAM_INT); // optional roleid, 0 menas all enrolled users (or all on the frontpage)
23 $contextid = optional_param('contextid', 0, PARAM_INT); // one of this or
24 $courseid = optional_param('id', 0, PARAM_INT); // this are required
26 $PAGE->set_url('/user/index.php', array(
27 'page' => $page,
28 'perpage' => $perpage,
29 'mode' => $mode,
30 'accesssince' => $accesssince,
31 'search' => $search,
32 'roleid' => $roleid,
33 'contextid' => $contextid,
34 'courseid' => $courseid));
36 if ($contextid) {
37 $context = get_context_instance_by_id($contextid, MUST_EXIST);
38 if ($context->contextlevel != CONTEXT_COURSE) {
39 print_error('invalidcontext');
41 $course = $DB->get_record('course', array('id'=>$context->instanceid), '*', MUST_EXIST);
42 } else {
43 $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
44 $context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST);
46 // not needed anymore
47 unset($contextid);
48 unset($courseid);
50 require_login($course);
52 $systemcontext = get_context_instance(CONTEXT_SYSTEM);
53 $isfrontpage = ($course->id == SITEID);
55 $frontpagectx = get_context_instance(CONTEXT_COURSE, SITEID);
57 if ($isfrontpage) {
58 $PAGE->set_pagelayout('admin');
59 require_capability('moodle/site:viewparticipants', $systemcontext);
60 } else {
61 $PAGE->set_pagelayout('incourse');
62 require_capability('moodle/course:viewparticipants', $context);
65 $rolenamesurl = new moodle_url("$CFG->wwwroot/user/index.php?contextid=$context->id&sifirst=&silast=");
67 $allroles = get_all_roles();
68 $roles = get_profile_roles($context);
69 $allrolenames = array();
70 if ($isfrontpage) {
71 $rolenames = array(0=>get_string('allsiteusers', 'role'));
72 } else {
73 $rolenames = array(0=>get_string('allparticipants'));
76 foreach ($allroles as $role) {
77 $allrolenames[$role->id] = strip_tags(role_get_name($role, $context)); // Used in menus etc later on
78 if (isset($roles[$role->id])) {
79 $rolenames[$role->id] = $allrolenames[$role->id];
83 // make sure other roles may not be selected by any means
84 if (empty($rolenames[$roleid])) {
85 print_error('noparticipants');
88 // no roles to display yet?
89 // frontpage course is an exception, on the front page course we should display all users
90 if (empty($rolenames) && !$isfrontpage) {
91 if (has_capability('moodle/role:assign', $context)) {
92 redirect($CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id);
93 } else {
94 print_error('noparticipants');
98 add_to_log($course->id, 'user', 'view all', 'index.php?id='.$course->id, '');
100 $bulkoperations = has_capability('moodle/course:bulkmessaging', $context);
102 $countries = get_string_manager()->get_list_of_countries();
104 $strnever = get_string('never');
106 $datestring->year = get_string('year');
107 $datestring->years = get_string('years');
108 $datestring->day = get_string('day');
109 $datestring->days = get_string('days');
110 $datestring->hour = get_string('hour');
111 $datestring->hours = get_string('hours');
112 $datestring->min = get_string('min');
113 $datestring->mins = get_string('mins');
114 $datestring->sec = get_string('sec');
115 $datestring->secs = get_string('secs');
117 if ($mode !== NULL) {
118 $mode = (int)$mode;
119 $SESSION->userindexmode = $mode;
120 } else if (isset($SESSION->userindexmode)) {
121 $mode = (int)$SESSION->userindexmode;
122 } else {
123 $mode = MODE_BRIEF;
126 /// Check to see if groups are being used in this course
127 /// and if so, set $currentgroup to reflect the current group
129 $groupmode = groups_get_course_groupmode($course); // Groups are being used
130 $currentgroup = groups_get_course_group($course, true);
132 if (!$currentgroup) { // To make some other functions work better later
133 $currentgroup = NULL;
136 $isseparategroups = ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context));
138 if ($course->id===SITEID) {
139 $PAGE->navbar->ignore_active();
142 $PAGE->navbar->add(get_string('participants'));
143 $PAGE->set_title("$course->shortname: ".get_string('participants'));
144 $PAGE->set_heading($course->fullname);
145 $PAGE->set_pagetype('course-view-' . $course->format);
146 $PAGE->add_body_class('path-user'); // So we can style it independently
147 $PAGE->set_other_editing_capability('moodle/course:manageactivities');
149 echo $OUTPUT->header();
151 echo '<div class="userlist">';
153 if ($isseparategroups and (!$currentgroup) ) {
154 // The user is not in the group so show message and exit
155 echo $OUTPUT->heading(get_string("notingroup"));
156 echo $OUTPUT->footer();
157 exit;
161 // Should use this variable so that we don't break stuff every time a variable is added or changed.
162 $baseurl = new moodle_url('/user/index.php', array(
163 'contextid' => $context->id,
164 'roleid' => $roleid,
165 'id' => $course->id,
166 'perpage' => $perpage,
167 'accesssince' => $accesssince,
168 'search' => s($search)));
170 /// setting up tags
171 if ($course->id == SITEID) {
172 $filtertype = 'site';
173 } else if ($course->id && !$currentgroup) {
174 $filtertype = 'course';
175 $filterselect = $course->id;
176 } else {
177 $filtertype = 'group';
178 $filterselect = $currentgroup;
183 /// Get the hidden field list
184 if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
185 $hiddenfields = array(); // teachers and admins are allowed to see everything
186 } else {
187 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
190 if (isset($hiddenfields['lastaccess'])) {
191 // do not allow access since filtering
192 $accesssince = 0;
195 /// Print settings and things in a table across the top
196 $controlstable = new html_table();
197 $controlstable->attributes['class'] = 'controls';
198 $controlstable->cellspacing = 0;
199 $controlstable->data[] = new html_table_row();
201 /// Print my course menus
202 if ($mycourses = get_my_courses($USER->id)) {
203 $courselist = array();
204 $popupurl = new moodle_url('/user/index.php?roleid='.$roleid.'&sifirst=&silast=');
205 foreach ($mycourses as $mycourse) {
206 $courselist[$mycourse->id] = format_string($mycourse->shortname);
208 if (has_capability('moodle/site:viewparticipants', $systemcontext)) {
209 unset($courselist[SITEID]);
210 $courselist = array(SITEID => format_string($SITE->shortname)) + $courselist;
212 $select = new single_select($popupurl, 'id', $courselist, $course->id, array(''=>'choosedots'), 'courseform');
213 $select->set_label(get_string('mycourses'));
214 $controlstable->data[0]->cells[] = $OUTPUT->render($select);
217 $controlstable->data[0]->cells[] = groups_print_course_menu($course, $baseurl->out());
219 if (!isset($hiddenfields['lastaccess'])) {
220 // get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far.
221 // we need to make it diferently for normal courses and site course
222 if (!$isfrontpage) {
223 $minlastaccess = $DB->get_field_sql('SELECT min(timeaccess)
224 FROM {user_lastaccess}
225 WHERE courseid = ?
226 AND timeaccess != 0', array($course->id));
227 $lastaccess0exists = $DB->record_exists('user_lastaccess', array('courseid'=>$course->id, 'timeaccess'=>0));
228 } else {
229 $minlastaccess = $DB->get_field_sql('SELECT min(lastaccess)
230 FROM {user}
231 WHERE lastaccess != 0');
232 $lastaccess0exists = $DB->record_exists('user', array('lastaccess'=>0));
235 $now = usergetmidnight(time());
236 $timeaccess = array();
237 $baseurl->remove_params('accesssince');
239 // makes sense for this to go first.
240 $timeoptions[0] = get_string('selectperiod');
242 // days
243 for ($i = 1; $i < 7; $i++) {
244 if (strtotime('-'.$i.' days',$now) >= $minlastaccess) {
245 $timeoptions[strtotime('-'.$i.' days',$now)] = get_string('numdays','moodle',$i);
248 // weeks
249 for ($i = 1; $i < 10; $i++) {
250 if (strtotime('-'.$i.' weeks',$now) >= $minlastaccess) {
251 $timeoptions[strtotime('-'.$i.' weeks',$now)] = get_string('numweeks','moodle',$i);
254 // months
255 for ($i = 2; $i < 12; $i++) {
256 if (strtotime('-'.$i.' months',$now) >= $minlastaccess) {
257 $timeoptions[strtotime('-'.$i.' months',$now)] = get_string('nummonths','moodle',$i);
260 // try a year
261 if (strtotime('-1 year',$now) >= $minlastaccess) {
262 $timeoptions[strtotime('-1 year',$now)] = get_string('lastyear');
265 if (!empty($lastaccess0exists)) {
266 $timeoptions[-1] = get_string('never');
269 if (count($timeoptions) > 1) {
270 $select = new single_select($baseurl, 'accesssince', $timeoptions, $accesssince, null, 'timeoptions');
271 $select->set_label(get_string('usersnoaccesssince'));
272 $controlstable->data[0]->cells[] = $OUTPUT->render($select);
276 // Decide wheteher we will fetch extra enrolment/groups data.
278 // MODE_ENROLDETAILS is expensive, and only suitable where the listing is small
279 // (at or below DEFAULT_PAGE_SIZE) and $USER can enrol/unenrol
280 // (will take 1 extra DB query - 2 on Oracle)
282 if (!$isfrontpage && ($perpage <= DEFAULT_PAGE_SIZE) && has_capability('moodle/role:assign',$context)) {
283 $allowenroldetails = true;
284 } else {
285 $allowenroldetails = false;
286 if ($mode === MODE_ENROLDETAILS) {
287 // conditions haven't been met - reset
288 $mode = MODE_BRIEF;
292 $formatmenu = array( '0' => get_string('brief'),
293 '1' => get_string('userdetails'));
294 if ($allowenroldetails) {
295 $formatmenu['2']= get_string('enroldetails');
297 $select = new single_select($baseurl, 'mode', $formatmenu, $mode, null, 'formatmenu');
298 $select->set_label(get_string('userlist'));
299 $userlistcell = new html_table_cell();
300 $userlistcell->attributes['class'] = 'right';
301 $userlistcell->text = $OUTPUT->render($select);
302 $controlstable->data[0]->cells[] = $userlistcell;
304 echo html_writer::table($controlstable);
306 if ($currentgroup and (!$isseparategroups or has_capability('moodle/site:accessallgroups', $context))) { /// Display info about the group
307 if ($group = groups_get_group($currentgroup)) {
308 if (!empty($group->description) or (!empty($group->picture) and empty($group->hidepicture))) {
309 $groupinfotable = new html_table();
310 $groupinfotable->attributes['class'] = 'groupinfobox';
311 $picturecell = new html_table_cell();
312 $picturecell->attributes['class'] = 'left side picture';
313 $picturecell->text = print_group_picture($group, $course->id, true, false, false);
315 $contentcell = new html_table_cell();
316 $contentcell->attributes['class'] = 'content';
317 $contentcell->text = print_group_picture($group, $course->id, true, false, false);
319 $contentheading = $group->name;
320 if (has_capability('moodle/course:managegroups', $context)) {
321 $aurl = new moodle_url('/group/group.php', array('id' => $group->id, 'courseid' => $group->courseid));
322 $contentheading .= '&nbsp;' . $OUTPUT->action_icon($aurl, new pix_icon('t/edit', get_string('editgroupprofile')));
325 $group->description = file_rewrite_pluginfile_urls($group->description, 'pluginfile.php', $context->id, 'course_group_description', $group->id);
326 if (!isset($group->descriptionformat)) {
327 $group->descriptionformat = FORMAT_MOODLE;
329 $contentcell->text = $OUTPUT->heading($contentheading, 3) . format_text($group->description, $group->descriptionformat);
330 $groupinfotable->data[] = new html_table_row(array($picturecell, $contentcell));
331 echo html_writer::table($groupinfotable);
336 /// Define a table showing a list of users in the current role selection
338 $tablecolumns = array('userpic', 'fullname');
339 $tableheaders = array(get_string('userpic'), get_string('fullnameuser'));
340 if ($mode === MODE_BRIEF && !isset($hiddenfields['city'])) {
341 $tablecolumns[] = 'city';
342 $tableheaders[] = get_string('city');
344 if ($mode === MODE_BRIEF && !isset($hiddenfields['country'])) {
345 $tablecolumns[] = 'country';
346 $tableheaders[] = get_string('country');
348 if (!isset($hiddenfields['lastaccess'])) {
349 $tablecolumns[] = 'lastaccess';
350 $tableheaders[] = get_string('lastaccess');
353 if ($course->enrolperiod and $roleid) {
354 $tablecolumns[] = 'timeend';
355 $tableheaders[] = get_string('enrolmentend');
358 if ($mode === MODE_ENROLDETAILS) {
359 $tablecolumns[] = 'roles';
360 $tableheaders[] = get_string('roles');
361 if ($groupmode != 0) {
362 $tablecolumns[] = 'groups';
363 $tableheaders[] = get_string('groups');
364 $tablecolumns[] = 'groupings';
365 $tableheaders[] = get_string('groupings', 'group');
369 if ($bulkoperations) {
370 $tablecolumns[] = 'select';
371 $tableheaders[] = get_string('select');
374 $table = new flexible_table('user-index-participants-'.$course->id);
376 $table->define_columns($tablecolumns);
377 $table->define_headers($tableheaders);
378 $table->define_baseurl($baseurl->out());
380 if (!isset($hiddenfields['lastaccess'])) {
381 $table->sortable(true, 'lastaccess', SORT_DESC);
384 $table->no_sorting('roles');
385 $table->no_sorting('groups');
386 $table->no_sorting('groupings');
387 $table->no_sorting('select');
389 $table->set_attribute('cellspacing', '0');
390 $table->set_attribute('id', 'participants');
391 $table->set_attribute('class', 'generaltable generalbox');
393 $table->set_control_variables(array(
394 TABLE_VAR_SORT => 'ssort',
395 TABLE_VAR_HIDE => 'shide',
396 TABLE_VAR_SHOW => 'sshow',
397 TABLE_VAR_IFIRST => 'sifirst',
398 TABLE_VAR_ILAST => 'silast',
399 TABLE_VAR_PAGE => 'spage'
401 $table->setup();
403 // we are looking for all users with this role assigned in this context or higher
404 $contextlist = get_related_contexts_string($context);
406 list($esql, $params) = get_enrolled_sql($context, NULL, $currentgroup, 'eu');
407 $joins = array("FROM {user} u");
408 $wheres = array();
410 if ($isfrontpage) {
411 $select = "SELECT u.id, u.username, u.firstname, u.lastname,
412 u.email, u.city, u.country, u.picture,
413 u.lang, u.timezone, u.emailstop, u.maildisplay, u.imagealt,
414 u.lastaccess";
415 $joins[] = "JOIN ($esql) e ON e.id = u.id"; // everybody on the frontpage usually
416 if ($accesssince) {
417 $wheres[] = get_user_lastaccess_sql($accesssince);
420 } else {
421 $select = "SELECT u.id, u.username, u.firstname, u.lastname,
422 u.email, u.city, u.country, u.picture,
423 u.lang, u.timezone, u.emailstop, u.maildisplay, u.imagealt,
424 COALESCE(ul.timeaccess, 0) AS lastaccess";
425 $joins[] = "JOIN ($esql) e ON e.id = u.id"; // course enrolled users only
426 $joins[] = "LEFT JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = :courseid)"; // not everybody accessed course yet
427 $params['courseid'] = $course->id;
428 if ($accesssince) {
429 $wheres[] = get_course_lastaccess_sql($accesssince);
432 if ($course->enrolperiod) {
433 // note: this is extremely tricky now, we do not know which ra assignment
434 // is the one causing enrolment - better show it onl when filtering by roles
436 if ($roleid) {
437 $select .= ", (SELECT MAX(rax.timeend) FROM {role_assignments} rax WHERE rax.userid = u.id AND rax.contextid $contextlist AND rax.roleid = :raxroleid) AS timeend";
438 $params['raxroleid'] = $roleid;
443 // performance hacks - we preload user contexts together with accounts
444 list($ccselect, $ccjoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx');
445 $select .= $ccselect;
446 $joins[] = $ccjoin;
449 // limit list to users with some role only
450 if ($roleid) {
451 $wheres[] = "u.id IN (SELECT userid FROM {role_assignments} WHERE roleid = :roleid AND contextid $contextlist)";
452 $params['roleid'] = $roleid;
455 $from = implode("\n", $joins);
456 if ($wheres) {
457 $where = "WHERE " . implode(" AND ", $wheres);
458 } else {
459 $where = "";
462 $totalcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params);
464 if (!empty($search)) {
465 $LIKE = $DB->sql_ilike();
466 $fullname = $DB->sql_fullname('u.firstname','u.lastname');
467 $wheres[] = "($fullname $LIKE :search1 OR email $LIKE :search2 OR idnumber $LIKE :search3) ";
468 $params['search1'] = "%$search%";
469 $params['search2'] = "%$search%";
470 $params['search3'] = "%$search%";
473 if ($table->get_sql_where()) {
474 $wheres[] = $table->get_sql_where();
477 $from = implode("\n", $joins);
478 if ($wheres) {
479 $where = "WHERE " . implode(" AND ", $wheres);
480 } else {
481 $where = "";
484 if ($table->get_sql_sort()) {
485 $sort = ' ORDER BY '.$table->get_sql_sort();
486 } else {
487 $sort = '';
490 $matchcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params);
492 $table->initialbars(true);
493 $table->pagesize($perpage, $matchcount);
495 // list of users at the current visible page - paging makes it relatively short
496 $userlist = $DB->get_recordset_sql("$select $from $where $sort", $params, $table->get_page_start(), $table->get_page_size());
499 // The SELECT behind get_participants_extra() is cheaper if we pass an array
500 // if IDs. We could pass the SELECT we did before (with the limit bits - tricky!)
501 // but this is much cheaper. And in any case, it is only doable with limited numbers
502 // of rows anyway. On a large course it will explode badly...
504 if ($mode === MODE_ENROLDETAILS) {
505 $userids = $DB->get_fieldset_sql("SELECT u.id $from $where", $params, $table->get_page_start(), $table->get_page_size());
506 $userlist_extra = get_participants_extra($userids, $course, $context);
509 /// If there are multiple Roles in the course, then show a drop down menu for switching
510 if (count($rolenames) > 1) {
511 echo '<div class="rolesform">';
512 echo '<label for="rolesform_jump">'.get_string('currentrole', 'role').'&nbsp;</label>';
513 echo $OUTPUT->single_select($rolenamesurl, 'roleid', $rolenames, $roleid, null, 'rolesform');
514 echo '</div>';
516 } else if (count($rolenames) == 1) {
517 // when all users with the same role - print its name
518 echo '<div class="rolesform">';
519 echo get_string('role').': ';
520 $rolename = reset($rolenames);
521 echo $rolename;
522 echo '</div>';
525 if ($roleid > 0) {
526 $a->number = $totalcount;
527 $a->role = $rolenames[$roleid];
528 $heading = format_string(get_string('xuserswiththerole', 'role', $a));
530 if ($currentgroup and $group) {
531 $a->group = $group->name;
532 $heading .= ' ' . format_string(get_string('ingroup', 'role', $a));
535 if ($accesssince) {
536 $a->timeperiod = $timeoptions[$accesssince];
537 $heading .= ' ' . format_string(get_string('inactiveformorethan', 'role', $a));
540 $heading .= ": $a->number";
541 if (user_can_assign($context, $roleid)) {
542 $heading .= ' <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?roleid='.$roleid.'&amp;contextid='.$context->id.'">';
543 $heading .= '<img src="'.$OUTPUT->pix_url('i/edit') . '" class="icon" alt="" /></a>';
545 echo $OUTPUT->heading($heading, 3);
546 } else {
547 if ($course->id != SITEID && has_capability('moodle/role:assign', $context)) {
548 $editlink = ' <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id.'">';
549 $editlink .= '<img src="'.$OUTPUT->pix_url('i/edit') . '" class="icon" alt="" /></a>';
550 } else {
551 $editlink = '';
553 if ($course->id == SITEID and $roleid < 0) {
554 $strallparticipants = get_string('allsiteusers', 'role');
555 } else {
556 $strallparticipants = get_string('allparticipants');
558 if ($matchcount < $totalcount) {
559 echo $OUTPUT->heading($strallparticipants.': '.$matchcount.'/'.$totalcount . $editlink, 3);
560 } else {
561 echo $OUTPUT->heading($strallparticipants.': '.$matchcount . $editlink, 3);
566 if ($bulkoperations) {
567 echo '<form action="action_redir.php" method="post" id="participantsform">';
568 echo '<div>';
569 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
570 echo '<input type="hidden" name="returnto" value="'.s(me()).'" />';
573 if ($CFG->longtimenosee > 0 && $CFG->longtimenosee < 1000 && $totalcount > 0) {
574 echo '<p id="longtimenosee">('.get_string('unusedaccounts', '', $CFG->longtimenosee).')</p>';
577 if ($mode === MODE_USERDETAILS) { // Print simple listing
578 if ($totalcount < 1) {
579 echo $OUTPUT->heading(get_string('nothingtodisplay'));
580 } else {
581 if ($totalcount > $perpage) {
583 $firstinitial = $table->get_initial_first();
584 $lastinitial = $table->get_initial_last();
585 $strall = get_string('all');
586 $alpha = explode(',', get_string('alphabet', 'langconfig'));
588 // Bar of first initials
590 echo '<div class="initialbar firstinitial">'.get_string('firstname').' : ';
591 if(!empty($firstinitial)) {
592 echo '<a href="'.$baseurl->out().'&amp;sifirst=">'.$strall.'</a>';
593 } else {
594 echo '<strong>'.$strall.'</strong>';
596 foreach ($alpha as $letter) {
597 if ($letter == $firstinitial) {
598 echo ' <strong>'.$letter.'</strong>';
599 } else {
600 echo ' <a href="'.$baseurl->out().'&amp;sifirst='.$letter.'">'.$letter.'</a>';
603 echo '</div>';
605 // Bar of last initials
607 echo '<div class="initialbar lastinitial">'.get_string('lastname').' : ';
608 if(!empty($lastinitial)) {
609 echo '<a href="'.$baseurl->out().'&amp;silast=">'.$strall.'</a>';
610 } else {
611 echo '<strong>'.$strall.'</strong>';
613 foreach ($alpha as $letter) {
614 if ($letter == $lastinitial) {
615 echo ' <strong>'.$letter.'</strong>';
616 } else {
617 echo ' <a href="'.$baseurl->out().'&amp;silast='.$letter.'">'.$letter.'</a>';
620 echo '</div>';
622 $pagingbar = new paging_bar($matchcount, intval($table->get_page_start() / $perpage), $perpage, $baseurl);
623 $pagingbar->pagevar = 'spage';
624 echo $OUTPUT->render($pagingbar);
627 if ($matchcount > 0) {
628 $usersprinted = array();
629 foreach ($userlist as $user) {
630 if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935
631 continue;
633 $usersprinted[] = $user->id; /// Add new user to the array of users printed
635 context_instance_preload($user);
637 $context = get_context_instance(CONTEXT_COURSE, $course->id);
638 $usercontext = get_context_instance(CONTEXT_USER, $user->id);
640 $countries = get_string_manager()->get_list_of_countries();
642 /// Get the hidden field list
643 if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
644 $hiddenfields = array();
645 } else {
646 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
648 $table = new html_table();
649 $table->attributes['class'] = 'userinfobox';
651 $row = new html_table_row();
652 $row->cells[0] = new html_table_cell();
653 $row->cells[0]->attributes['class'] = 'left side';
655 $row->cells[0]->text = $OUTPUT->user_picture($user, array('courseid'=>$course->id));
656 $row->cells[1] = new html_table_cell();
657 $row->cells[1]->attributes['class'] = 'content';
659 $row->cells[1]->text = $OUTPUT->container(fullname($user, has_capability('moodle/site:viewfullnames', $context)), 'username');
660 $row->cells[1]->text .= $OUTPUT->container_start('info');
662 if (!empty($user->role)) {
663 $row->cells[1]->text .= get_string('role') .': '. $user->role .'<br />';
665 if ($user->maildisplay == 1 or ($user->maildisplay == 2 and ($course->id != SITEID) and !isguestuser()) or
666 has_capability('moodle/course:viewhiddenuserfields', $context)) {
667 $row->cells[1]->text .= get_string('email') .': ' . html_writer::link("mailto:$user->email", $user->email) . '<br />';
669 if (($user->city or $user->country) and (!isset($hiddenfields['city']) or !isset($hiddenfields['country']))) {
670 $row->cells[1]->text .= get_string('city') .': ';
671 if ($user->city && !isset($hiddenfields['city'])) {
672 $row->cells[1]->text .= $user->city;
674 if (!empty($countries[$user->country]) && !isset($hiddenfields['country'])) {
675 if ($user->city && !isset($hiddenfields['city'])) {
676 $row->cells[1]->text .= ', ';
678 $row->cells[1]->text .= $countries[$user->country];
680 $row->cells[1]->text .= '<br />';
683 if (!isset($hiddenfields['lastaccess'])) {
684 if ($user->lastaccess) {
685 $row->cells[1]->text .= get_string('lastaccess') .': '. userdate($user->lastaccess);
686 $row->cells[1]->text .= '&nbsp; ('. format_time(time() - $user->lastaccess, $datestring) .')';
687 } else {
688 $row->cells[1]->text .= get_string('lastaccess') .': '. get_string('never');
692 $row->cells[1]->text .= $OUTPUT->container_end();
694 $row->cells[2] = new html_table_cell();
695 $row->cells[2]->attributes['class'] = 'links';
696 $row->cells[2]->text = '';
698 $links = array();
700 if ($CFG->bloglevel > 0) {
701 $links[] = html_writer::link(new moodle_url('/blog/index.php?userid='.$user->id), get_string('blogs','blog'));
704 if (!empty($CFG->enablenotes) and (has_capability('moodle/notes:manage', $context) || has_capability('moodle/notes:view', $context))) {
705 $links[] = html_writer::link(new moodle_url('/notes/index.php?course=' . $course->id. '&user='.$user->id), get_string('notes','notes'));
708 if (has_capability('moodle/site:viewreports', $context) or has_capability('moodle/user:viewuseractivitiesreport', $usercontext)) {
709 $links[] = html_writer::link(new moodle_url('/course/user.php?id='. $course->id .'&user='. $user->id), get_string('activity'));
712 if (has_capability('moodle/role:assign', $context) and get_user_roles($context, $user->id, false)) { // I can unassign and user has some role
713 $links[] = html_writer::link(new moodle_url('/course/unenrol.php?id='. $course->id .'&user='. $user->id), get_string('unenrol'));
716 if ($USER->id != $user->id && !session_is_loggedinas() && has_capability('moodle/user:loginas', $context) && !is_siteadmin($user->id)) {
717 $links[] = html_writer::link(new moodle_url('/course/loginas.php?id='. $course->id .'&user='. $user->id .'&sesskey='. sesskey()), get_string('loginas'));
720 $links[] = html_writer::link(new moodle_url('/user/view.php?id='. $user->id .'&course='. $course->id), get_string('fullprofile') . '...');
722 $row->cells[2]->text .= implode('', $links);
724 if (!empty($messageselect)) {
725 $row->cells[2]->text .= '<br /><input type="checkbox" name="user'.$user->id.'" /> ';
727 $table->data = array($row);
728 echo html_writer::table($table);
731 } else {
732 echo $OUTPUT->heading(get_string('nothingtodisplay'));
736 } else {
737 $countrysort = (strpos($sort, 'country') !== false);
738 $timeformat = get_string('strftimedate');
741 if ($userlist) {
743 // only show the plugin if multiple enrolment plugins
744 // are enabled...
745 if (strpos($CFG->enrol_plugins_enabled, ',')=== false) {
746 $showenrolplugin = true;
747 } else {
748 $showenrolplugin = false;
751 $usersprinted = array();
752 foreach ($userlist as $user) {
753 if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935
754 continue;
756 $usersprinted[] = $user->id; /// Add new user to the array of users printed
758 context_instance_preload($user);
760 if ($user->lastaccess) {
761 $lastaccess = format_time(time() - $user->lastaccess, $datestring);
762 } else {
763 $lastaccess = $strnever;
766 if (empty($user->country)) {
767 $country = '';
769 } else {
770 if($countrysort) {
771 $country = '('.$user->country.') '.$countries[$user->country];
773 else {
774 $country = $countries[$user->country];
778 $usercontext = get_context_instance(CONTEXT_USER, $user->id);
780 if ($piclink = ($USER->id == $user->id || has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext))) {
781 $profilelink = '<strong><a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.fullname($user).'</a></strong>';
782 } else {
783 $profilelink = '<strong>'.fullname($user).'</strong>';
786 $data = array ($OUTPUT->user_picture($user, array('courseid'=>$course->id)), $profilelink);
788 if ($mode === MODE_BRIEF && !isset($hiddenfields['city'])) {
789 $data[] = $user->city;
791 if ($mode === MODE_BRIEF && !isset($hiddenfields['country'])) {
792 $data[] = $country;
794 if (!isset($hiddenfields['lastaccess'])) {
795 $data[] = $lastaccess;
797 if ($course->enrolperiod and $roleid) {
798 if ($user->timeend) {
799 $data[] = userdate($user->timeend, $timeformat);
800 } else {
801 $data[] = get_string('unlimited');
805 if (isset($userlist_extra) && isset($userlist_extra[$user->id])) {
806 $ras = $userlist_extra[$user->id]['ra'];
807 $rastring = '';
808 foreach ($ras AS $key=>$ra) {
809 $rolename = $allrolenames[$ra['roleid']] ;
810 if ($ra['ctxlevel'] == CONTEXT_COURSECAT) {
811 $rastring .= $rolename. ' @ ' . '<a href="'.$CFG->wwwroot.'/course/category.php?id='.$ra['ctxinstanceid'].'">'.s($ra['ccname']).'</a>';
812 } elseif ($ra['ctxlevel'] == CONTEXT_SYSTEM) {
813 $rastring .= $rolename. ' - ' . get_string('globalrole','role');
814 } else {
815 $rastring .= $rolename;
817 if ($showenrolplugin) {
818 $rastring .= '<br />';
819 } else {
820 $rastring .= ' ('. $ra['enrolplugin'] .')<br />';
823 $data[] = $rastring;
824 if ($groupmode != 0) {
825 // htmlescape with s() and implode the array
826 $data[] = implode(', ', array_map('s',$userlist_extra[$user->id]['group']));
827 $data[] = implode(', ', array_map('s', $userlist_extra[$user->id]['gping']));
831 if ($bulkoperations) {
832 $data[] = '<input type="checkbox" class="usercheckbox" name="user'.$user->id.'" />';
834 $table->add_data($data);
839 $table->print_html();
843 if ($bulkoperations) {
844 echo '<br /><div class="buttons">';
845 echo '<input type="button" id="checkall" value="'.get_string('selectall').'" /> ';
846 echo '<input type="button" id="checknone" value="'.get_string('deselectall').'" /> ';
847 $displaylist = array();
848 $displaylist['messageselect.php'] = get_string('messageselectadd');
849 if (!empty($CFG->enablenotes) && has_capability('moodle/notes:manage', $context) && $context->id != $frontpagectx->id) {
850 $displaylist['addnote.php'] = get_string('addnewnote', 'notes');
851 $displaylist['groupaddnote.php'] = get_string('groupaddnewnote', 'notes');
854 if ($context->id != $frontpagectx->id) {
855 $displaylist['extendenrol.php'] = get_string('extendenrol');
856 $displaylist['groupextendenrol.php'] = get_string('groupextendenrol');
859 echo $OUTPUT->old_help_icon("participantswithselectedusers", get_string("withselectedusers"));
860 echo html_writer::tag('label', get_string("withselectedusers"), array('for'=>'formactionid'));
861 echo html_writer::select($displaylist, 'formaction', '', array(''=>'choosedots'), array('id'=>'formactionid'));
863 echo '<input type="hidden" name="id" value="'.$course->id.'" />';
864 echo '<noscript style="display:inline">';
865 echo '<input type="submit" value="'.get_string('ok').'" />';
866 echo '</noscript>';
867 echo '</div></div>';
868 echo '</form>';
870 $module = array('name'=>'core_user', 'fullpath'=>'/user/module.js');
871 $PAGE->requires->js_init_call('M.core_user.init_participation', null, false, $module);
874 if (has_capability('moodle/site:viewparticipants', $context) && $totalcount > ($perpage*3)) {
875 echo '<form action="index.php" class="searchform"><div><input type="hidden" name="id" value="'.$course->id.'" />'.get_string('search').':&nbsp;'."\n";
876 echo '<input type="text" name="search" value="'.s($search).'" />&nbsp;<input type="submit" value="'.get_string('search').'" /></div></form>'."\n";
879 $perpageurl = clone($baseurl);
880 $perpageurl->remove_params('perpage');
881 if ($perpage == SHOW_ALL_PAGE_SIZE) {
882 $perpageurl->param('perpage', DEFAULT_PAGE_SIZE);
883 echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showperpage', '', DEFAULT_PAGE_SIZE)), array(), 'showall');
885 } else if ($matchcount > 0 && $perpage < $matchcount) {
886 $perpageurl->param('perpage', SHOW_ALL_PAGE_SIZE);
887 echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showall', '', $matchcount)), array(), 'showall');
890 echo '</div>'; // userlist
892 echo $OUTPUT->footer();
894 if ($userlist) {
895 $userlist->close();
899 function get_course_lastaccess_sql($accesssince='') {
900 if (empty($accesssince)) {
901 return '';
903 if ($accesssince == -1) { // never
904 return 'ul.timeaccess = 0';
905 } else {
906 return 'ul.timeaccess != 0 AND ul.timeaccess < '.$accesssince;
910 function get_user_lastaccess_sql($accesssince='') {
911 if (empty($accesssince)) {
912 return '';
914 if ($accesssince == -1) { // never
915 return 'u.lastaccess = 0';
916 } else {
917 return 'u.lastaccess != 0 AND u.lastaccess < '.$accesssince;
921 function get_participants_extra ($userids, $course, $context) {
922 global $CFG, $DB;
924 if (count($userids) === 0) {
925 return array();
928 $params = array();
930 $userids = implode(',', $userids);
932 // turn the path into a list of context ids
933 $contextids = substr($context->path, 1); // kill leading slash
934 $contextids = str_replace('/', ',', $contextids);;
936 $gpjoin = "LEFT OUTER JOIN {groupings_groups} gpg
937 ON gpg.groupid=g.id
938 LEFT OUTER JOIN {groupings} gp
939 ON (gp.courseid={$course->id} AND gp.id=gpg.groupingid)";
940 $gpselect = ',gp.id AS gpid, gp.name AS gpname ';
942 // Note: this returns strange redundant rows, perhaps
943 // due to the multiple OUTER JOINs. If we can tweak the
944 // JOINs to avoid it ot
945 $sql = "SELECT DISTINCT ra.userid,
946 ctx.id AS ctxid, ctx.path AS ctxpath, ctx.depth AS ctxdepth,
947 ctx.contextlevel AS ctxlevel, ctx.instanceid AS ctxinstanceid,
948 cc.name AS ccname,
949 ra.roleid AS roleid,
950 ra.enrol AS enrolplugin,
951 g.id AS gid, g.name AS gname
952 $gpselect
953 FROM {role_assignments} ra
954 JOIN {context} ctx
955 ON (ra.contextid=ctx.id)
956 LEFT JOIN {course_categories} cc
957 ON (ctx.contextlevel=40 AND ctx.instanceid=cc.id)
959 /* only if groups active */
960 LEFT JOIN {groups_members} gm
961 ON (ra.userid=gm.userid)
962 LEFT JOIN {groups} g
963 ON (gm.groupid=g.id AND g.courseid={$course->id})
964 /* and if groupings is enabled... */
965 $gpjoin
967 WHERE ra.userid IN ( $userids )
968 AND ra.contextid in ( $contextids )
970 ORDER BY ra.userid, ctx.depth DESC";
972 $rs = $DB->get_recordset_sql($sql, $params);
973 $extra = array();
975 // Data structure -
976 // $extra [ $userid ] [ 'group' ] [ $groupid => 'group name']
977 // [ 'gping' ] [ $gpingid => 'gping name']
978 // [ 'ra' ] [ [ "$ctxid:$roleid" => [ctxid => $ctxid
979 // ctxdepth => $ctxdepth,
980 // ctxpath => $ctxpath,
981 // ctxname => 'name' (categories only)
982 // ctxinstid =>
983 // roleid => $roleid
984 // enrol => $pluginname
986 // Might be interesting to add to RA timestart, timeend, timemodified,
987 // and modifierid (with an outer join to mdl_user!
990 foreach ($rs as $rec) {
991 $userid = $rec->userid;
993 // Prime an initial user rec...
994 if (!isset($extra[$userid])) {
995 $extra[$userid] = array( 'group' => array(),
996 'gping' => array(),
997 'ra' => array() );
1000 if (!empty($rec->gid)) {
1001 $extra[$userid]['group'][$rec->gid]= $rec->gname;
1003 if (!empty($rec->gpid)) {
1004 $extra[$userid]['gping'][$rec->gpid]= $rec->gpname;
1006 $rakey = $rec->ctxid . ':' . $rec->roleid;
1007 if (!isset($extra[$userid]['ra'][$rakey])) {
1008 $extra[$userid]['ra'][$rakey] = array('ctxid' => $rec->ctxid,
1009 'ctxlevel' => $rec->ctxlevel,
1010 'ctxinstanceid' => $rec->ctxinstanceid,
1011 'ccname' => $rec->ccname,
1012 'roleid' => $rec->roleid,
1013 'enrolplugin' => $rec->enrolplugin);
1017 $rs->close();
1018 return $extra;