global search MDL-24625 added page system context
[moodle.git] / user / index.php
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);
15     $page         = optional_param('page', 0, PARAM_INT);                     // which page to show
16     $perpage      = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT);  // how many per page
17     $mode         = optional_param('mode', NULL, PARAM_INT);                  // use the MODE_ constants
18     $accesssince  = optional_param('accesssince',0,PARAM_INT);                // filter by last access. -1 = never
19     $search       = optional_param('search','',PARAM_RAW);                    // make sure it is processed with p() or s() when sending to output!
20     $roleid       = optional_param('roleid', 0, PARAM_INT);                   // optional roleid, 0 means all enrolled users (or all on the frontpage)
22     $contextid    = optional_param('contextid', 0, PARAM_INT);                // one of this or
23     $courseid     = optional_param('id', 0, PARAM_INT);                       // this are required
25     $PAGE->set_url('/user/index.php', array(
26             'page' => $page,
27             'perpage' => $perpage,
28             'mode' => $mode,
29             'accesssince' => $accesssince,
30             'search' => $search,
31             'roleid' => $roleid,
32             'contextid' => $contextid,
33             'courseid' => $courseid));
35     if ($contextid) {
36         $context = get_context_instance_by_id($contextid, MUST_EXIST);
37         if ($context->contextlevel != CONTEXT_COURSE) {
38             print_error('invalidcontext');
39         }
40         $course = $DB->get_record('course', array('id'=>$context->instanceid), '*', MUST_EXIST);
41     } else {
42         $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
43         $context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST);
44     }
45     // not needed anymore
46     unset($contextid);
47     unset($courseid);
49     require_login($course);
51     $systemcontext = get_context_instance(CONTEXT_SYSTEM);
52     $isfrontpage = ($course->id == SITEID);
54     $frontpagectx = get_context_instance(CONTEXT_COURSE, SITEID);
56     if ($isfrontpage) {
57         $PAGE->set_pagelayout('admin');
58         require_capability('moodle/site:viewparticipants', $systemcontext);
59     } else {
60         $PAGE->set_pagelayout('incourse');
61         require_capability('moodle/course:viewparticipants', $context);
62     }
64     $rolenamesurl = new moodle_url("$CFG->wwwroot/user/index.php?contextid=$context->id&sifirst=&silast=");
66     $allroles = get_all_roles();
67     $roles = get_profile_roles($context);
68     $allrolenames = array();
69     if ($isfrontpage) {
70         $rolenames = array(0=>get_string('allsiteusers', 'role'));
71     } else {
72         $rolenames = array(0=>get_string('allparticipants'));
73     }
75     foreach ($allroles as $role) {
76         $allrolenames[$role->id] = strip_tags(role_get_name($role, $context));   // Used in menus etc later on
77         if (isset($roles[$role->id])) {
78             $rolenames[$role->id] = $allrolenames[$role->id];
79         }
80     }
82     // make sure other roles may not be selected by any means
83     if (empty($rolenames[$roleid])) {
84         print_error('noparticipants');
85     }
87     // no roles to display yet?
88     // frontpage course is an exception, on the front page course we should display all users
89     if (empty($rolenames) && !$isfrontpage) {
90         if (has_capability('moodle/role:assign', $context)) {
91             redirect($CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id);
92         } else {
93             print_error('noparticipants');
94         }
95     }
97     add_to_log($course->id, 'user', 'view all', 'index.php?id='.$course->id, '');
99     $bulkoperations = has_capability('moodle/course:bulkmessaging', $context);
101     $countries = get_string_manager()->get_list_of_countries();
103     $strnever = get_string('never');
105     $datestring->year  = get_string('year');
106     $datestring->years = get_string('years');
107     $datestring->day   = get_string('day');
108     $datestring->days  = get_string('days');
109     $datestring->hour  = get_string('hour');
110     $datestring->hours = get_string('hours');
111     $datestring->min   = get_string('min');
112     $datestring->mins  = get_string('mins');
113     $datestring->sec   = get_string('sec');
114     $datestring->secs  = get_string('secs');
116     if ($mode !== NULL) {
117         $mode = (int)$mode;
118         $SESSION->userindexmode = $mode;
119     } else if (isset($SESSION->userindexmode)) {
120         $mode = (int)$SESSION->userindexmode;
121     } else {
122         $mode = MODE_BRIEF;
123     }
125 /// Check to see if groups are being used in this course
126 /// and if so, set $currentgroup to reflect the current group
128     $groupmode    = groups_get_course_groupmode($course);   // Groups are being used
129     $currentgroup = groups_get_course_group($course, true);
131     if (!$currentgroup) {      // To make some other functions work better later
132         $currentgroup  = NULL;
133     }
135     $isseparategroups = ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context));
137     if ($course->id===SITEID) {
138         $PAGE->navbar->ignore_active();
139     }
141     $PAGE->navbar->add(get_string('participants'));
142     $PAGE->set_title("$course->shortname: ".get_string('participants'));
143     $PAGE->set_heading($course->fullname);
144     $PAGE->set_pagetype('course-view-' . $course->format);
145     $PAGE->add_body_class('path-user');                     // So we can style it independently
146     $PAGE->set_other_editing_capability('moodle/course:manageactivities');
148     echo $OUTPUT->header();
150     echo '<div class="userlist">';
152     if ($isseparategroups and (!$currentgroup) ) {
153         // The user is not in the group so show message and exit
154         echo $OUTPUT->heading(get_string("notingroup"));
155         echo $OUTPUT->footer();
156         exit;
157     }
160     // Should use this variable so that we don't break stuff every time a variable is added or changed.
161     $baseurl = new moodle_url('/user/index.php', array(
162             'contextid' => $context->id,
163             'roleid' => $roleid,
164             'id' => $course->id,
165             'perpage' => $perpage,
166             'accesssince' => $accesssince,
167             'search' => s($search)));
169 /// setting up tags
170     if ($course->id == SITEID) {
171         $filtertype = 'site';
172     } else if ($course->id && !$currentgroup) {
173         $filtertype = 'course';
174         $filterselect = $course->id;
175     } else {
176         $filtertype = 'group';
177         $filterselect = $currentgroup;
178     }
182 /// Get the hidden field list
183     if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
184         $hiddenfields = array();  // teachers and admins are allowed to see everything
185     } else {
186         $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
187     }
189     if (isset($hiddenfields['lastaccess'])) {
190         // do not allow access since filtering
191         $accesssince = 0;
192     }
194 /// Print settings and things in a table across the top
195     $controlstable = new html_table();
196     $controlstable->attributes['class'] = 'controls';
197     $controlstable->cellspacing = 0;
198     $controlstable->data[] = new html_table_row();
200 /// Print my course menus
201     if ($mycourses = enrol_get_my_courses()) {
202         $courselist = array();
203         $popupurl = new moodle_url('/user/index.php?roleid='.$roleid.'&sifirst=&silast=');
204         foreach ($mycourses as $mycourse) {
205             $courselist[$mycourse->id] = format_string($mycourse->shortname);
206         }
207         if (has_capability('moodle/site:viewparticipants', $systemcontext)) {
208             unset($courselist[SITEID]);
209             $courselist = array(SITEID => format_string($SITE->shortname)) + $courselist;
210         }
211         $select = new single_select($popupurl, 'id', $courselist, $course->id, array(''=>'choosedots'), 'courseform');
212         $select->set_label(get_string('mycourses'));
213         $controlstable->data[0]->cells[] = $OUTPUT->render($select);
214     }
216     $controlstable->data[0]->cells[] = groups_print_course_menu($course, $baseurl->out(), true);
218     if (!isset($hiddenfields['lastaccess'])) {
219         // get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far.
220         // we need to make it diferently for normal courses and site course
221         if (!$isfrontpage) {
222             $minlastaccess = $DB->get_field_sql('SELECT min(timeaccess)
223                                                    FROM {user_lastaccess}
224                                                   WHERE courseid = ?
225                                                         AND timeaccess != 0', array($course->id));
226             $lastaccess0exists = $DB->record_exists('user_lastaccess', array('courseid'=>$course->id, 'timeaccess'=>0));
227         } else {
228             $minlastaccess = $DB->get_field_sql('SELECT min(lastaccess)
229                                                    FROM {user}
230                                                   WHERE lastaccess != 0');
231             $lastaccess0exists = $DB->record_exists('user', array('lastaccess'=>0));
232         }
234         $now = usergetmidnight(time());
235         $timeaccess = array();
236         $baseurl->remove_params('accesssince');
238         // makes sense for this to go first.
239         $timeoptions[0] = get_string('selectperiod');
241         // days
242         for ($i = 1; $i < 7; $i++) {
243             if (strtotime('-'.$i.' days',$now) >= $minlastaccess) {
244                 $timeoptions[strtotime('-'.$i.' days',$now)] = get_string('numdays','moodle',$i);
245             }
246         }
247         // weeks
248         for ($i = 1; $i < 10; $i++) {
249             if (strtotime('-'.$i.' weeks',$now) >= $minlastaccess) {
250                 $timeoptions[strtotime('-'.$i.' weeks',$now)] = get_string('numweeks','moodle',$i);
251             }
252         }
253         // months
254         for ($i = 2; $i < 12; $i++) {
255             if (strtotime('-'.$i.' months',$now) >= $minlastaccess) {
256                 $timeoptions[strtotime('-'.$i.' months',$now)] = get_string('nummonths','moodle',$i);
257             }
258         }
259         // try a year
260         if (strtotime('-1 year',$now) >= $minlastaccess) {
261             $timeoptions[strtotime('-1 year',$now)] = get_string('lastyear');
262         }
264         if (!empty($lastaccess0exists)) {
265             $timeoptions[-1] = get_string('never');
266         }
268         if (count($timeoptions) > 1) {
269             $select = new single_select($baseurl, 'accesssince', $timeoptions, $accesssince, null, 'timeoptions');
270             $select->set_label(get_string('usersnoaccesssince'));
271             $controlstable->data[0]->cells[] = $OUTPUT->render($select);
272         }
273     }
275     $formatmenu = array( '0' => get_string('brief'),
276                          '1' => get_string('userdetails'));
277     $select = new single_select($baseurl, 'mode', $formatmenu, $mode, null, 'formatmenu');
278     $select->set_label(get_string('userlist'));
279     $userlistcell = new html_table_cell();
280     $userlistcell->attributes['class'] = 'right';
281     $userlistcell->text = $OUTPUT->render($select);
282     $controlstable->data[0]->cells[] = $userlistcell;
284     echo html_writer::table($controlstable);
286     if ($currentgroup and (!$isseparategroups or has_capability('moodle/site:accessallgroups', $context))) {    /// Display info about the group
287         if ($group = groups_get_group($currentgroup)) {
288             if (!empty($group->description) or (!empty($group->picture) and empty($group->hidepicture))) {
289                 $groupinfotable = new html_table();
290                 $groupinfotable->attributes['class'] = 'groupinfobox';
291                 $picturecell = new html_table_cell();
292                 $picturecell->attributes['class'] = 'left side picture';
293                 $picturecell->text = print_group_picture($group, $course->id, true, true, false);
295                 $contentcell = new html_table_cell();
296                 $contentcell->attributes['class'] = 'content';
298                 $contentheading = $group->name;
299                 if (has_capability('moodle/course:managegroups', $context)) {
300                     $aurl = new moodle_url('/group/group.php', array('id' => $group->id, 'courseid' => $group->courseid));
301                     $contentheading .= '&nbsp;' . $OUTPUT->action_icon($aurl, new pix_icon('t/edit', get_string('editgroupprofile')));
302                 }
304                 $group->description = file_rewrite_pluginfile_urls($group->description, 'pluginfile.php', $context->id, 'group', 'description', $group->id);
305                 if (!isset($group->descriptionformat)) {
306                     $group->descriptionformat = FORMAT_MOODLE;
307                 }
308                 $contentcell->text = $OUTPUT->heading($contentheading, 3) . format_text($group->description, $group->descriptionformat);
309                 $groupinfotable->data[] = new html_table_row(array($picturecell, $contentcell));
310                 echo html_writer::table($groupinfotable);
311             }
312         }
313     }
315     /// Define a table showing a list of users in the current role selection
317     $tablecolumns = array('userpic', 'fullname');
318     $tableheaders = array(get_string('userpic'), get_string('fullnameuser'));
319     if ($mode === MODE_BRIEF && !isset($hiddenfields['city'])) {
320         $tablecolumns[] = 'city';
321         $tableheaders[] = get_string('city');
322     }
323     if ($mode === MODE_BRIEF && !isset($hiddenfields['country'])) {
324         $tablecolumns[] = 'country';
325         $tableheaders[] = get_string('country');
326     }
327     if (!isset($hiddenfields['lastaccess'])) {
328         $tablecolumns[] = 'lastaccess';
329         $tableheaders[] = get_string('lastaccess');
330     }
332     if ($bulkoperations) {
333         $tablecolumns[] = 'select';
334         $tableheaders[] = get_string('select');
335     }
337     $table = new flexible_table('user-index-participants-'.$course->id);
339     $table->define_columns($tablecolumns);
340     $table->define_headers($tableheaders);
341     $table->define_baseurl($baseurl->out());
343     if (!isset($hiddenfields['lastaccess'])) {
344         $table->sortable(true, 'lastaccess', SORT_DESC);
345     }
347     $table->no_sorting('roles');
348     $table->no_sorting('groups');
349     $table->no_sorting('groupings');
350     $table->no_sorting('select');
352     $table->set_attribute('cellspacing', '0');
353     $table->set_attribute('id', 'participants');
354     $table->set_attribute('class', 'generaltable generalbox');
356     $table->set_control_variables(array(
357                 TABLE_VAR_SORT    => 'ssort',
358                 TABLE_VAR_HIDE    => 'shide',
359                 TABLE_VAR_SHOW    => 'sshow',
360                 TABLE_VAR_IFIRST  => 'sifirst',
361                 TABLE_VAR_ILAST   => 'silast',
362                 TABLE_VAR_PAGE    => 'spage'
363                 ));
364     $table->setup();
366     // we are looking for all users with this role assigned in this context or higher
367     $contextlist = get_related_contexts_string($context);
369     list($esql, $params) = get_enrolled_sql($context, NULL, $currentgroup);
370     $joins = array("FROM {user} u");
371     $wheres = array();
373     if ($isfrontpage) {
374         $select = "SELECT u.id, u.username, u.firstname, u.lastname,
375                           u.email, u.city, u.country, u.picture,
376                           u.lang, u.timezone, u.emailstop, u.maildisplay, u.imagealt,
377                           u.lastaccess";
378         $joins[] = "JOIN ($esql) e ON e.id = u.id"; // everybody on the frontpage usually
379         if ($accesssince) {
380             $wheres[] = get_user_lastaccess_sql($accesssince);
381         }
383     } else {
384         $select = "SELECT u.id, u.username, u.firstname, u.lastname,
385                           u.email, u.city, u.country, u.picture,
386                           u.lang, u.timezone, u.emailstop, u.maildisplay, u.imagealt,
387                           COALESCE(ul.timeaccess, 0) AS lastaccess";
388         $joins[] = "JOIN ($esql) e ON e.id = u.id"; // course enrolled users only
389         $joins[] = "LEFT JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = :courseid)"; // not everybody accessed course yet
390         $params['courseid'] = $course->id;
391         if ($accesssince) {
392             $wheres[] = get_course_lastaccess_sql($accesssince);
393         }
394     }
396     // performance hacks - we preload user contexts together with accounts
397     list($ccselect, $ccjoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx');
398     $select .= $ccselect;
399     $joins[] = $ccjoin;
402     // limit list to users with some role only
403     if ($roleid) {
404         $wheres[] = "u.id IN (SELECT userid FROM {role_assignments} WHERE roleid = :roleid AND contextid $contextlist)";
405         $params['roleid'] = $roleid;
406     }
408     $from = implode("\n", $joins);
409     if ($wheres) {
410         $where = "WHERE " . implode(" AND ", $wheres);
411     } else {
412         $where = "";
413     }
415     $totalcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params);
417     if (!empty($search)) {
418         $fullname = $DB->sql_fullname('u.firstname','u.lastname');
419         $wheres[] = "(". $DB->sql_like($fullname, ':search1', false, false) .
420                     " OR ". $DB->sql_like('email', ':search2', false, false) .
421                     " OR ". $DB->sql_like('idnumber', ':search3', false, false) .") ";
422         $params['search1'] = "%$search%";
423         $params['search2'] = "%$search%";
424         $params['search3'] = "%$search%";
425     }
427     list($twhere, $tparams) = $table->get_sql_where();
428     if ($twhere) {
429         $wheres[] = $twhere;
430         $params = array_merge($params, $tparams);
431     }
433     $from = implode("\n", $joins);
434     if ($wheres) {
435         $where = "WHERE " . implode(" AND ", $wheres);
436     } else {
437         $where = "";
438     }
440     if ($table->get_sql_sort()) {
441         $sort = ' ORDER BY '.$table->get_sql_sort();
442     } else {
443         $sort = '';
444     }
446     $matchcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params);
448     $table->initialbars(true);
449     $table->pagesize($perpage, $matchcount);
451     // list of users at the current visible page - paging makes it relatively short
452     $userlist = $DB->get_recordset_sql("$select $from $where $sort", $params, $table->get_page_start(), $table->get_page_size());
454     /// If there are multiple Roles in the course, then show a drop down menu for switching
455     if (count($rolenames) > 1) {
456         echo '<div class="rolesform">';
457         echo '<label for="rolesform_jump">'.get_string('currentrole', 'role').'&nbsp;</label>';
458         echo $OUTPUT->single_select($rolenamesurl, 'roleid', $rolenames, $roleid, null, 'rolesform');
459         echo '</div>';
461     } else if (count($rolenames) == 1) {
462         // when all users with the same role - print its name
463         echo '<div class="rolesform">';
464         echo get_string('role').get_string('labelsep', 'langconfig');
465         $rolename = reset($rolenames);
466         echo $rolename;
467         echo '</div>';
468     }
470     if ($roleid > 0) {
471         $a->number = $totalcount;
472         $a->role = $rolenames[$roleid];
473         $heading = format_string(get_string('xuserswiththerole', 'role', $a));
475         if ($currentgroup and $group) {
476             $a->group = $group->name;
477             $heading .= ' ' . format_string(get_string('ingroup', 'role', $a));
478         }
480         if ($accesssince) {
481             $a->timeperiod = $timeoptions[$accesssince];
482             $heading .= ' ' . format_string(get_string('inactiveformorethan', 'role', $a));
483         }
485         $heading .= ": $a->number";
486         if (user_can_assign($context, $roleid)) {
487             $heading .= ' <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?roleid='.$roleid.'&amp;contextid='.$context->id.'">';
488             $heading .= '<img src="'.$OUTPUT->pix_url('i/edit') . '" class="icon" alt="" /></a>';
489         }
490         echo $OUTPUT->heading($heading, 3);
491     } else {
492         if ($course->id != SITEID && has_capability('moodle/course:enrolreview', $context)) {
493             $editlink = $OUTPUT->action_icon(new moodle_url('/enrol/users.php', array('id' => $course->id)),
494                                              new pix_icon('i/edit', get_string('edit')));
495         } else {
496             $editlink = '';
497         }
498         if ($course->id == SITEID and $roleid < 0) {
499             $strallparticipants = get_string('allsiteusers', 'role');
500         } else {
501             $strallparticipants = get_string('allparticipants');
502         }
503         if ($matchcount < $totalcount) {
504             echo $OUTPUT->heading($strallparticipants.get_string('labelsep', 'langconfig').$matchcount.'/'.$totalcount . $editlink, 3);
505         } else {
506             echo $OUTPUT->heading($strallparticipants.get_string('labelsep', 'langconfig').$matchcount . $editlink, 3);
507         }
508     }
511     if ($bulkoperations) {
512         echo '<form action="action_redir.php" method="post" id="participantsform">';
513         echo '<div>';
514         echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
515         echo '<input type="hidden" name="returnto" value="'.s(me()).'" />';
516     }
518     if ($mode === MODE_USERDETAILS) {    // Print simple listing
519         if ($totalcount < 1) {
520             echo $OUTPUT->heading(get_string('nothingtodisplay'));
521         } else {
522             if ($totalcount > $perpage) {
524                 $firstinitial = $table->get_initial_first();
525                 $lastinitial  = $table->get_initial_last();
526                 $strall = get_string('all');
527                 $alpha  = explode(',', get_string('alphabet', 'langconfig'));
529                 // Bar of first initials
531                 echo '<div class="initialbar firstinitial">'.get_string('firstname').' : ';
532                 if(!empty($firstinitial)) {
533                     echo '<a href="'.$baseurl->out().'&amp;sifirst=">'.$strall.'</a>';
534                 } else {
535                     echo '<strong>'.$strall.'</strong>';
536                 }
537                 foreach ($alpha as $letter) {
538                     if ($letter == $firstinitial) {
539                         echo ' <strong>'.$letter.'</strong>';
540                     } else {
541                         echo ' <a href="'.$baseurl->out().'&amp;sifirst='.$letter.'">'.$letter.'</a>';
542                     }
543                 }
544                 echo '</div>';
546                 // Bar of last initials
548                 echo '<div class="initialbar lastinitial">'.get_string('lastname').' : ';
549                 if(!empty($lastinitial)) {
550                     echo '<a href="'.$baseurl->out().'&amp;silast=">'.$strall.'</a>';
551                 } else {
552                     echo '<strong>'.$strall.'</strong>';
553                 }
554                 foreach ($alpha as $letter) {
555                     if ($letter == $lastinitial) {
556                         echo ' <strong>'.$letter.'</strong>';
557                     } else {
558                         echo ' <a href="'.$baseurl->out().'&amp;silast='.$letter.'">'.$letter.'</a>';
559                     }
560                 }
561                 echo '</div>';
563                 $pagingbar = new paging_bar($matchcount, intval($table->get_page_start() / $perpage), $perpage, $baseurl);
564                 $pagingbar->pagevar = 'spage';
565                 echo $OUTPUT->render($pagingbar);
566             }
568             if ($matchcount > 0) {
569                 $usersprinted = array();
570                 foreach ($userlist as $user) {
571                     if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935
572                         continue;
573                     }
574                     $usersprinted[] = $user->id; /// Add new user to the array of users printed
576                     context_instance_preload($user);
578                     $context = get_context_instance(CONTEXT_COURSE, $course->id);
579                     $usercontext = get_context_instance(CONTEXT_USER, $user->id);
581                     $countries = get_string_manager()->get_list_of_countries();
583                     /// Get the hidden field list
584                     if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
585                         $hiddenfields = array();
586                     } else {
587                         $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
588                     }
589                     $table = new html_table();
590                     $table->attributes['class'] = 'userinfobox';
592                     $row = new html_table_row();
593                     $row->cells[0] = new html_table_cell();
594                     $row->cells[0]->attributes['class'] = 'left side';
596                     $row->cells[0]->text = $OUTPUT->user_picture($user, array('courseid'=>$course->id));
597                     $row->cells[1] = new html_table_cell();
598                     $row->cells[1]->attributes['class'] = 'content';
600                     $row->cells[1]->text = $OUTPUT->container(fullname($user, has_capability('moodle/site:viewfullnames', $context)), 'username');
601                     $row->cells[1]->text .= $OUTPUT->container_start('info');
603                     if (!empty($user->role)) {
604                         $row->cells[1]->text .= get_string('role').get_string('labelsep', 'langconfig').$user->role.'<br />';
605                     }
606                     if ($user->maildisplay == 1 or ($user->maildisplay == 2 and ($course->id != SITEID) and !isguestuser()) or
607                                 has_capability('moodle/course:viewhiddenuserfields', $context)) {
608                         $row->cells[1]->text .= get_string('email').get_string('labelsep', 'langconfig').html_writer::link("mailto:$user->email", $user->email) . '<br />';
609                     }
610                     if (($user->city or $user->country) and (!isset($hiddenfields['city']) or !isset($hiddenfields['country']))) {
611                         $row->cells[1]->text .= get_string('city').get_string('labelsep', 'langconfig');
612                         if ($user->city && !isset($hiddenfields['city'])) {
613                             $row->cells[1]->text .= $user->city;
614                         }
615                         if (!empty($countries[$user->country]) && !isset($hiddenfields['country'])) {
616                             if ($user->city && !isset($hiddenfields['city'])) {
617                                 $row->cells[1]->text .= ', ';
618                             }
619                             $row->cells[1]->text .= $countries[$user->country];
620                         }
621                         $row->cells[1]->text .= '<br />';
622                     }
624                     if (!isset($hiddenfields['lastaccess'])) {
625                         if ($user->lastaccess) {
626                             $row->cells[1]->text .= get_string('lastaccess').get_string('labelsep', 'langconfig').userdate($user->lastaccess);
627                             $row->cells[1]->text .= '&nbsp; ('. format_time(time() - $user->lastaccess, $datestring) .')';
628                         } else {
629                             $row->cells[1]->text .= get_string('lastaccess').get_string('labelsep', 'langconfig').get_string('never');
630                         }
631                     }
633                     $row->cells[1]->text .= $OUTPUT->container_end();
635                     $row->cells[2] = new html_table_cell();
636                     $row->cells[2]->attributes['class'] = 'links';
637                     $row->cells[2]->text = '';
639                     $links = array();
641                     if ($CFG->bloglevel > 0) {
642                         $links[] = html_writer::link(new moodle_url('/blog/index.php?userid='.$user->id), get_string('blogs','blog'));
643                     }
645                     if (!empty($CFG->enablenotes) and (has_capability('moodle/notes:manage', $context) || has_capability('moodle/notes:view', $context))) {
646                         $links[] = html_writer::link(new moodle_url('/notes/index.php?course=' . $course->id. '&user='.$user->id), get_string('notes','notes'));
647                     }
649                     if (has_capability('moodle/site:viewreports', $context) or has_capability('moodle/user:viewuseractivitiesreport', $usercontext)) {
650                         $links[] = html_writer::link(new moodle_url('/course/user.php?id='. $course->id .'&user='. $user->id), get_string('activity'));
651                     }
653                     if ($USER->id != $user->id && !session_is_loggedinas() && has_capability('moodle/user:loginas', $context) && !is_siteadmin($user->id)) {
654                         $links[] = html_writer::link(new moodle_url('/course/loginas.php?id='. $course->id .'&user='. $user->id .'&sesskey='. sesskey()), get_string('loginas'));
655                     }
657                     $links[] = html_writer::link(new moodle_url('/user/view.php?id='. $user->id .'&course='. $course->id), get_string('fullprofile') . '...');
659                     $row->cells[2]->text .= implode('', $links);
661                     if (!empty($messageselect)) {
662                         $row->cells[2]->text .= '<br /><input type="checkbox" name="user'.$user->id.'" /> ';
663                     }
664                     $table->data = array($row);
665                     echo html_writer::table($table);
666                 }
668             } else {
669                 echo $OUTPUT->heading(get_string('nothingtodisplay'));
670             }
671         }
673     } else {
674         $countrysort = (strpos($sort, 'country') !== false);
675         $timeformat = get_string('strftimedate');
678         if ($userlist)  {
680             $usersprinted = array();
681             foreach ($userlist as $user) {
682                 if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935
683                     continue;
684                 }
685                 $usersprinted[] = $user->id; /// Add new user to the array of users printed
687                 context_instance_preload($user);
689                 if ($user->lastaccess) {
690                     $lastaccess = format_time(time() - $user->lastaccess, $datestring);
691                 } else {
692                     $lastaccess = $strnever;
693                 }
695                 if (empty($user->country)) {
696                     $country = '';
698                 } else {
699                     if($countrysort) {
700                         $country = '('.$user->country.') '.$countries[$user->country];
701                     }
702                     else {
703                         $country = $countries[$user->country];
704                     }
705                 }
707                 $usercontext = get_context_instance(CONTEXT_USER, $user->id);
709                 if ($piclink = ($USER->id == $user->id || has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext))) {
710                     $profilelink = '<strong><a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.fullname($user).'</a></strong>';
711                 } else {
712                     $profilelink = '<strong>'.fullname($user).'</strong>';
713                 }
715                 $data = array ($OUTPUT->user_picture($user, array('courseid'=>$course->id)), $profilelink);
717                 if ($mode === MODE_BRIEF && !isset($hiddenfields['city'])) {
718                     $data[] = $user->city;
719                 }
720                 if ($mode === MODE_BRIEF && !isset($hiddenfields['country'])) {
721                     $data[] = $country;
722                 }
723                 if (!isset($hiddenfields['lastaccess'])) {
724                     $data[] = $lastaccess;
725                 }
727                 if (isset($userlist_extra) && isset($userlist_extra[$user->id])) {
728                     $ras = $userlist_extra[$user->id]['ra'];
729                     $rastring = '';
730                     foreach ($ras AS $key=>$ra) {
731                         $rolename = $allrolenames[$ra['roleid']] ;
732                         if ($ra['ctxlevel'] == CONTEXT_COURSECAT) {
733                             $rastring .= $rolename. ' @ ' . '<a href="'.$CFG->wwwroot.'/course/category.php?id='.$ra['ctxinstanceid'].'">'.s($ra['ccname']).'</a>';
734                         } elseif ($ra['ctxlevel'] == CONTEXT_SYSTEM) {
735                             $rastring .= $rolename. ' - ' . get_string('globalrole','role');
736                         } else {
737                             $rastring .= $rolename;
738                         }
739                     }
740                     $data[] = $rastring;
741                     if ($groupmode != 0) {
742                         // htmlescape with s() and implode the array
743                         $data[] = implode(', ', array_map('s',$userlist_extra[$user->id]['group']));
744                         $data[] = implode(', ', array_map('s', $userlist_extra[$user->id]['gping']));
745                     }
746                 }
748                 if ($bulkoperations) {
749                     $data[] = '<input type="checkbox" class="usercheckbox" name="user'.$user->id.'" />';
750                 }
751                 $table->add_data($data);
753             }
754         }
756         $table->print_html();
758     }
760     if ($bulkoperations) {
761         echo '<br /><div class="buttons">';
762         echo '<input type="button" id="checkall" value="'.get_string('selectall').'" /> ';
763         echo '<input type="button" id="checknone" value="'.get_string('deselectall').'" /> ';
764         $displaylist = array();
765         $displaylist['messageselect.php'] = get_string('messageselectadd');
766         if (!empty($CFG->enablenotes) && has_capability('moodle/notes:manage', $context) && $context->id != $frontpagectx->id) {
767             $displaylist['addnote.php'] = get_string('addnewnote', 'notes');
768             $displaylist['groupaddnote.php'] = get_string('groupaddnewnote', 'notes');
769         }
771         echo $OUTPUT->help_icon('withselectedusers');
772         echo html_writer::tag('label', get_string("withselectedusers"), array('for'=>'formactionid'));
773         echo html_writer::select($displaylist, 'formaction', '', array(''=>'choosedots'), array('id'=>'formactionid'));
775         echo '<input type="hidden" name="id" value="'.$course->id.'" />';
776         echo '<noscript style="display:inline">';
777         echo '<input type="submit" value="'.get_string('ok').'" />';
778         echo '</noscript>';
779         echo '</div></div>';
780         echo '</form>';
782         $module = array('name'=>'core_user', 'fullpath'=>'/user/module.js');
783         $PAGE->requires->js_init_call('M.core_user.init_participation', null, false, $module);
784     }
786     if (has_capability('moodle/site:viewparticipants', $context) && $totalcount > ($perpage*3)) {
787         echo '<form action="index.php" class="searchform"><div><input type="hidden" name="id" value="'.$course->id.'" />'.get_string('search').':&nbsp;'."\n";
788         echo '<input type="text" name="search" value="'.s($search).'" />&nbsp;<input type="submit" value="'.get_string('search').'" /></div></form>'."\n";
789     }
791     $perpageurl = clone($baseurl);
792     $perpageurl->remove_params('perpage');
793     if ($perpage == SHOW_ALL_PAGE_SIZE) {
794         $perpageurl->param('perpage', DEFAULT_PAGE_SIZE);
795         echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showperpage', '', DEFAULT_PAGE_SIZE)), array(), 'showall');
797     } else if ($matchcount > 0 && $perpage < $matchcount) {
798         $perpageurl->param('perpage', SHOW_ALL_PAGE_SIZE);
799         echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showall', '', $matchcount)), array(), 'showall');
800     }
802     echo '</div>';  // userlist
804     echo $OUTPUT->footer();
806     if ($userlist) {
807         $userlist->close();
808     }
811 function get_course_lastaccess_sql($accesssince='') {
812     if (empty($accesssince)) {
813         return '';
814     }
815     if ($accesssince == -1) { // never
816         return 'ul.timeaccess = 0';
817     } else {
818         return 'ul.timeaccess != 0 AND ul.timeaccess < '.$accesssince;
819     }
822 function get_user_lastaccess_sql($accesssince='') {
823     if (empty($accesssince)) {
824         return '';
825     }
826     if ($accesssince == -1) { // never
827         return 'u.lastaccess = 0';
828     } else {
829         return 'u.lastaccess != 0 AND u.lastaccess < '.$accesssince;
830     }
833 function get_participants_extra ($userids, $course, $context) {
834     global $CFG, $DB;
836     if (count($userids) === 0) {
837         return array();
838     }
840     $params = array();
842     $userids = implode(',', $userids);
844     // turn the path into a list of context ids
845     $contextids = substr($context->path, 1); // kill leading slash
846     $contextids = str_replace('/', ',', $contextids);;
848     $gpjoin = "LEFT OUTER JOIN {groupings_groups} gpg
849                     ON gpg.groupid=g.id
850                LEFT OUTER JOIN {groupings} gp
851                     ON (gp.courseid={$course->id} AND gp.id=gpg.groupingid)";
852     $gpselect = ',gp.id AS gpid, gp.name AS gpname ';
854     // Note: this returns strange redundant rows, perhaps
855     // due to the multiple OUTER JOINs. If we can tweak the
856     // JOINs to avoid it ot
857     $sql = "SELECT DISTINCT ra.userid,
858                    ctx.id AS ctxid, ctx.path AS ctxpath, ctx.depth AS ctxdepth,
859                    ctx.contextlevel AS ctxlevel, ctx.instanceid AS ctxinstanceid,
860                    cc.name  AS ccname,
861                    ra.roleid AS roleid,
862                    g.id     AS gid, g.name AS gname
863                    $gpselect
864               FROM {role_assignments} ra
865               JOIN {context} ctx
866                    ON (ra.contextid=ctx.id)
867               LEFT JOIN {course_categories} cc
868                    ON (ctx.contextlevel=40 AND ctx.instanceid=cc.id)
870             /* only if groups active */
871               LEFT JOIN {groups_members} gm
872                    ON (ra.userid=gm.userid)
873               LEFT JOIN {groups} g
874                    ON (gm.groupid=g.id AND g.courseid={$course->id})
875             /* and if groupings is enabled... */
876             $gpjoin
878              WHERE ra.userid IN ( $userids )
879                    AND ra.contextid in ( $contextids )
881           ORDER BY ra.userid, ctx.depth DESC";
883     $rs = $DB->get_recordset_sql($sql, $params);
884     $extra = array();
886     // Data structure -
887     // $extra [ $userid ] [ 'group' ] [ $groupid => 'group name']
888     //                    [ 'gping' ] [ $gpingid => 'gping name']
889     //                    [ 'ra' ] [  [ "$ctxid:$roleid" => [ctxid => $ctxid
890     //                                                       ctxdepth =>  $ctxdepth,
891     //                                                       ctxpath => $ctxpath,
892     //                                                       ctxname => 'name' (categories only)
893     //                                                       ctxinstid =>
894     //                                                       roleid => $roleid
896     foreach ($rs as $rec) {
897         $userid = $rec->userid;
899         // Prime an initial user rec...
900         if (!isset($extra[$userid])) {
901             $extra[$userid] = array( 'group' => array(),
902                                      'gping' => array(),
903                                      'ra'    => array() );
904         }
906         if (!empty($rec->gid)) {
907             $extra[$userid]['group'][$rec->gid]= $rec->gname;
908         }
909         if (!empty($rec->gpid)) {
910             $extra[$userid]['gping'][$rec->gpid]= $rec->gpname;
911         }
912         $rakey = $rec->ctxid . ':' . $rec->roleid;
913         if (!isset($extra[$userid]['ra'][$rakey])) {
914             $extra[$userid]['ra'][$rakey] = array('ctxid'         => $rec->ctxid,
915                                                   'ctxlevel'       => $rec->ctxlevel,
916                                                   'ctxinstanceid' => $rec->ctxinstanceid,
917                                                   'ccname'        => $rec->ccname,
918                                                   'roleid'        => $rec->roleid);
920         }
921     }
922     $rs->close();
923     return $extra;