MDL-22624 help string thanks to Davo Smith for suggested wording
[moodle.git] / user / index.php
blob02a169da6cae0c5719f8f0f7e29f5ad50c566814
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); // use the MODE_ constants
18 $accesssince = optional_param('accesssince',0,PARAM_INT); // filter by last access. -1 = never
19 $search = optional_param('search','',PARAM_CLEAN);
20 $roleid = optional_param('roleid', 0, PARAM_INT); // optional roleid, 0 menas 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');
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);
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);
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'));
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];
82 // make sure other roles may not be selected by any means
83 if (empty($rolenames[$roleid])) {
84 print_error('noparticipants');
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');
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;
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;
135 $isseparategroups = ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context));
137 if ($course->id===SITEID) {
138 $PAGE->navbar->ignore_active();
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;
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;
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));
189 if (isset($hiddenfields['lastaccess'])) {
190 // do not allow access since filtering
191 $accesssince = 0;
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);
207 if (has_capability('moodle/site:viewparticipants', $systemcontext)) {
208 unset($courselist[SITEID]);
209 $courselist = array(SITEID => format_string($SITE->shortname)) + $courselist;
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);
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));
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);
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);
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);
259 // try a year
260 if (strtotime('-1 year',$now) >= $minlastaccess) {
261 $timeoptions[strtotime('-1 year',$now)] = get_string('lastyear');
264 if (!empty($lastaccess0exists)) {
265 $timeoptions[-1] = get_string('never');
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);
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')));
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;
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);
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');
323 if ($mode === MODE_BRIEF && !isset($hiddenfields['country'])) {
324 $tablecolumns[] = 'country';
325 $tableheaders[] = get_string('country');
327 if (!isset($hiddenfields['lastaccess'])) {
328 $tablecolumns[] = 'lastaccess';
329 $tableheaders[] = get_string('lastaccess');
332 if ($bulkoperations) {
333 $tablecolumns[] = 'select';
334 $tableheaders[] = get_string('select');
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);
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'
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);
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);
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;
408 $from = implode("\n", $joins);
409 if ($wheres) {
410 $where = "WHERE " . implode(" AND ", $wheres);
411 } else {
412 $where = "";
415 $totalcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params);
417 if (!empty($search)) {
418 $LIKE = $DB->sql_ilike();
419 $fullname = $DB->sql_fullname('u.firstname','u.lastname');
420 $wheres[] = "($fullname $LIKE :search1 OR email $LIKE :search2 OR idnumber $LIKE :search3) ";
421 $params['search1'] = "%$search%";
422 $params['search2'] = "%$search%";
423 $params['search3'] = "%$search%";
426 if ($table->get_sql_where()) {
427 $wheres[] = $table->get_sql_where();
430 $from = implode("\n", $joins);
431 if ($wheres) {
432 $where = "WHERE " . implode(" AND ", $wheres);
433 } else {
434 $where = "";
437 if ($table->get_sql_sort()) {
438 $sort = ' ORDER BY '.$table->get_sql_sort();
439 } else {
440 $sort = '';
443 $matchcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params);
445 $table->initialbars(true);
446 $table->pagesize($perpage, $matchcount);
448 // list of users at the current visible page - paging makes it relatively short
449 $userlist = $DB->get_recordset_sql("$select $from $where $sort", $params, $table->get_page_start(), $table->get_page_size());
451 /// If there are multiple Roles in the course, then show a drop down menu for switching
452 if (count($rolenames) > 1) {
453 echo '<div class="rolesform">';
454 echo '<label for="rolesform_jump">'.get_string('currentrole', 'role').'&nbsp;</label>';
455 echo $OUTPUT->single_select($rolenamesurl, 'roleid', $rolenames, $roleid, null, 'rolesform');
456 echo '</div>';
458 } else if (count($rolenames) == 1) {
459 // when all users with the same role - print its name
460 echo '<div class="rolesform">';
461 echo get_string('role').get_string('labelsep', 'langconfig');
462 $rolename = reset($rolenames);
463 echo $rolename;
464 echo '</div>';
467 if ($roleid > 0) {
468 $a->number = $totalcount;
469 $a->role = $rolenames[$roleid];
470 $heading = format_string(get_string('xuserswiththerole', 'role', $a));
472 if ($currentgroup and $group) {
473 $a->group = $group->name;
474 $heading .= ' ' . format_string(get_string('ingroup', 'role', $a));
477 if ($accesssince) {
478 $a->timeperiod = $timeoptions[$accesssince];
479 $heading .= ' ' . format_string(get_string('inactiveformorethan', 'role', $a));
482 $heading .= ": $a->number";
483 if (user_can_assign($context, $roleid)) {
484 $heading .= ' <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?roleid='.$roleid.'&amp;contextid='.$context->id.'">';
485 $heading .= '<img src="'.$OUTPUT->pix_url('i/edit') . '" class="icon" alt="" /></a>';
487 echo $OUTPUT->heading($heading, 3);
488 } else {
489 if ($course->id != SITEID && has_capability('moodle/role:assign', $context)) {
490 $editlink = ' <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id.'">';
491 $editlink .= '<img src="'.$OUTPUT->pix_url('i/edit') . '" class="icon" alt="" /></a>';
492 } else {
493 $editlink = '';
495 if ($course->id == SITEID and $roleid < 0) {
496 $strallparticipants = get_string('allsiteusers', 'role');
497 } else {
498 $strallparticipants = get_string('allparticipants');
500 if ($matchcount < $totalcount) {
501 echo $OUTPUT->heading($strallparticipants.get_string('labelsep', 'langconfig').$matchcount.'/'.$totalcount . $editlink, 3);
502 } else {
503 echo $OUTPUT->heading($strallparticipants.get_string('labelsep', 'langconfig').$matchcount . $editlink, 3);
508 if ($bulkoperations) {
509 echo '<form action="action_redir.php" method="post" id="participantsform">';
510 echo '<div>';
511 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
512 echo '<input type="hidden" name="returnto" value="'.s(me()).'" />';
515 if ($mode === MODE_USERDETAILS) { // Print simple listing
516 if ($totalcount < 1) {
517 echo $OUTPUT->heading(get_string('nothingtodisplay'));
518 } else {
519 if ($totalcount > $perpage) {
521 $firstinitial = $table->get_initial_first();
522 $lastinitial = $table->get_initial_last();
523 $strall = get_string('all');
524 $alpha = explode(',', get_string('alphabet', 'langconfig'));
526 // Bar of first initials
528 echo '<div class="initialbar firstinitial">'.get_string('firstname').' : ';
529 if(!empty($firstinitial)) {
530 echo '<a href="'.$baseurl->out().'&amp;sifirst=">'.$strall.'</a>';
531 } else {
532 echo '<strong>'.$strall.'</strong>';
534 foreach ($alpha as $letter) {
535 if ($letter == $firstinitial) {
536 echo ' <strong>'.$letter.'</strong>';
537 } else {
538 echo ' <a href="'.$baseurl->out().'&amp;sifirst='.$letter.'">'.$letter.'</a>';
541 echo '</div>';
543 // Bar of last initials
545 echo '<div class="initialbar lastinitial">'.get_string('lastname').' : ';
546 if(!empty($lastinitial)) {
547 echo '<a href="'.$baseurl->out().'&amp;silast=">'.$strall.'</a>';
548 } else {
549 echo '<strong>'.$strall.'</strong>';
551 foreach ($alpha as $letter) {
552 if ($letter == $lastinitial) {
553 echo ' <strong>'.$letter.'</strong>';
554 } else {
555 echo ' <a href="'.$baseurl->out().'&amp;silast='.$letter.'">'.$letter.'</a>';
558 echo '</div>';
560 $pagingbar = new paging_bar($matchcount, intval($table->get_page_start() / $perpage), $perpage, $baseurl);
561 $pagingbar->pagevar = 'spage';
562 echo $OUTPUT->render($pagingbar);
565 if ($matchcount > 0) {
566 $usersprinted = array();
567 foreach ($userlist as $user) {
568 if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935
569 continue;
571 $usersprinted[] = $user->id; /// Add new user to the array of users printed
573 context_instance_preload($user);
575 $context = get_context_instance(CONTEXT_COURSE, $course->id);
576 $usercontext = get_context_instance(CONTEXT_USER, $user->id);
578 $countries = get_string_manager()->get_list_of_countries();
580 /// Get the hidden field list
581 if (has_capability('moodle/course:viewhiddenuserfields', $context)) {
582 $hiddenfields = array();
583 } else {
584 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields));
586 $table = new html_table();
587 $table->attributes['class'] = 'userinfobox';
589 $row = new html_table_row();
590 $row->cells[0] = new html_table_cell();
591 $row->cells[0]->attributes['class'] = 'left side';
593 $row->cells[0]->text = $OUTPUT->user_picture($user, array('courseid'=>$course->id));
594 $row->cells[1] = new html_table_cell();
595 $row->cells[1]->attributes['class'] = 'content';
597 $row->cells[1]->text = $OUTPUT->container(fullname($user, has_capability('moodle/site:viewfullnames', $context)), 'username');
598 $row->cells[1]->text .= $OUTPUT->container_start('info');
600 if (!empty($user->role)) {
601 $row->cells[1]->text .= get_string('role').get_string('labelsep', 'langconfig').$user->role.'<br />';
603 if ($user->maildisplay == 1 or ($user->maildisplay == 2 and ($course->id != SITEID) and !isguestuser()) or
604 has_capability('moodle/course:viewhiddenuserfields', $context)) {
605 $row->cells[1]->text .= get_string('email').get_string('labelsep', 'langconfig').html_writer::link("mailto:$user->email", $user->email) . '<br />';
607 if (($user->city or $user->country) and (!isset($hiddenfields['city']) or !isset($hiddenfields['country']))) {
608 $row->cells[1]->text .= get_string('city').get_string('labelsep', 'langconfig');
609 if ($user->city && !isset($hiddenfields['city'])) {
610 $row->cells[1]->text .= $user->city;
612 if (!empty($countries[$user->country]) && !isset($hiddenfields['country'])) {
613 if ($user->city && !isset($hiddenfields['city'])) {
614 $row->cells[1]->text .= ', ';
616 $row->cells[1]->text .= $countries[$user->country];
618 $row->cells[1]->text .= '<br />';
621 if (!isset($hiddenfields['lastaccess'])) {
622 if ($user->lastaccess) {
623 $row->cells[1]->text .= get_string('lastaccess').get_string('labelsep', 'langconfig').userdate($user->lastaccess);
624 $row->cells[1]->text .= '&nbsp; ('. format_time(time() - $user->lastaccess, $datestring) .')';
625 } else {
626 $row->cells[1]->text .= get_string('lastaccess').get_string('labelsep', 'langconfig').get_string('never');
630 $row->cells[1]->text .= $OUTPUT->container_end();
632 $row->cells[2] = new html_table_cell();
633 $row->cells[2]->attributes['class'] = 'links';
634 $row->cells[2]->text = '';
636 $links = array();
638 if ($CFG->bloglevel > 0) {
639 $links[] = html_writer::link(new moodle_url('/blog/index.php?userid='.$user->id), get_string('blogs','blog'));
642 if (!empty($CFG->enablenotes) and (has_capability('moodle/notes:manage', $context) || has_capability('moodle/notes:view', $context))) {
643 $links[] = html_writer::link(new moodle_url('/notes/index.php?course=' . $course->id. '&user='.$user->id), get_string('notes','notes'));
646 if (has_capability('moodle/site:viewreports', $context) or has_capability('moodle/user:viewuseractivitiesreport', $usercontext)) {
647 $links[] = html_writer::link(new moodle_url('/course/user.php?id='. $course->id .'&user='. $user->id), get_string('activity'));
650 if ($USER->id != $user->id && !session_is_loggedinas() && has_capability('moodle/user:loginas', $context) && !is_siteadmin($user->id)) {
651 $links[] = html_writer::link(new moodle_url('/course/loginas.php?id='. $course->id .'&user='. $user->id .'&sesskey='. sesskey()), get_string('loginas'));
654 $links[] = html_writer::link(new moodle_url('/user/view.php?id='. $user->id .'&course='. $course->id), get_string('fullprofile') . '...');
656 $row->cells[2]->text .= implode('', $links);
658 if (!empty($messageselect)) {
659 $row->cells[2]->text .= '<br /><input type="checkbox" name="user'.$user->id.'" /> ';
661 $table->data = array($row);
662 echo html_writer::table($table);
665 } else {
666 echo $OUTPUT->heading(get_string('nothingtodisplay'));
670 } else {
671 $countrysort = (strpos($sort, 'country') !== false);
672 $timeformat = get_string('strftimedate');
675 if ($userlist) {
677 $usersprinted = array();
678 foreach ($userlist as $user) {
679 if (in_array($user->id, $usersprinted)) { /// Prevent duplicates by r.hidden - MDL-13935
680 continue;
682 $usersprinted[] = $user->id; /// Add new user to the array of users printed
684 context_instance_preload($user);
686 if ($user->lastaccess) {
687 $lastaccess = format_time(time() - $user->lastaccess, $datestring);
688 } else {
689 $lastaccess = $strnever;
692 if (empty($user->country)) {
693 $country = '';
695 } else {
696 if($countrysort) {
697 $country = '('.$user->country.') '.$countries[$user->country];
699 else {
700 $country = $countries[$user->country];
704 $usercontext = get_context_instance(CONTEXT_USER, $user->id);
706 if ($piclink = ($USER->id == $user->id || has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext))) {
707 $profilelink = '<strong><a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.fullname($user).'</a></strong>';
708 } else {
709 $profilelink = '<strong>'.fullname($user).'</strong>';
712 $data = array ($OUTPUT->user_picture($user, array('courseid'=>$course->id)), $profilelink);
714 if ($mode === MODE_BRIEF && !isset($hiddenfields['city'])) {
715 $data[] = $user->city;
717 if ($mode === MODE_BRIEF && !isset($hiddenfields['country'])) {
718 $data[] = $country;
720 if (!isset($hiddenfields['lastaccess'])) {
721 $data[] = $lastaccess;
724 if (isset($userlist_extra) && isset($userlist_extra[$user->id])) {
725 $ras = $userlist_extra[$user->id]['ra'];
726 $rastring = '';
727 foreach ($ras AS $key=>$ra) {
728 $rolename = $allrolenames[$ra['roleid']] ;
729 if ($ra['ctxlevel'] == CONTEXT_COURSECAT) {
730 $rastring .= $rolename. ' @ ' . '<a href="'.$CFG->wwwroot.'/course/category.php?id='.$ra['ctxinstanceid'].'">'.s($ra['ccname']).'</a>';
731 } elseif ($ra['ctxlevel'] == CONTEXT_SYSTEM) {
732 $rastring .= $rolename. ' - ' . get_string('globalrole','role');
733 } else {
734 $rastring .= $rolename;
737 $data[] = $rastring;
738 if ($groupmode != 0) {
739 // htmlescape with s() and implode the array
740 $data[] = implode(', ', array_map('s',$userlist_extra[$user->id]['group']));
741 $data[] = implode(', ', array_map('s', $userlist_extra[$user->id]['gping']));
745 if ($bulkoperations) {
746 $data[] = '<input type="checkbox" class="usercheckbox" name="user'.$user->id.'" />';
748 $table->add_data($data);
753 $table->print_html();
757 if ($bulkoperations) {
758 echo '<br /><div class="buttons">';
759 echo '<input type="button" id="checkall" value="'.get_string('selectall').'" /> ';
760 echo '<input type="button" id="checknone" value="'.get_string('deselectall').'" /> ';
761 $displaylist = array();
762 $displaylist['messageselect.php'] = get_string('messageselectadd');
763 if (!empty($CFG->enablenotes) && has_capability('moodle/notes:manage', $context) && $context->id != $frontpagectx->id) {
764 $displaylist['addnote.php'] = get_string('addnewnote', 'notes');
765 $displaylist['groupaddnote.php'] = get_string('groupaddnewnote', 'notes');
768 echo $OUTPUT->help_icon('withselectedusers');
769 echo html_writer::tag('label', get_string("withselectedusers"), array('for'=>'formactionid'));
770 echo html_writer::select($displaylist, 'formaction', '', array(''=>'choosedots'), array('id'=>'formactionid'));
772 echo '<input type="hidden" name="id" value="'.$course->id.'" />';
773 echo '<noscript style="display:inline">';
774 echo '<input type="submit" value="'.get_string('ok').'" />';
775 echo '</noscript>';
776 echo '</div></div>';
777 echo '</form>';
779 $module = array('name'=>'core_user', 'fullpath'=>'/user/module.js');
780 $PAGE->requires->js_init_call('M.core_user.init_participation', null, false, $module);
783 if (has_capability('moodle/site:viewparticipants', $context) && $totalcount > ($perpage*3)) {
784 echo '<form action="index.php" class="searchform"><div><input type="hidden" name="id" value="'.$course->id.'" />'.get_string('search').':&nbsp;'."\n";
785 echo '<input type="text" name="search" value="'.s($search).'" />&nbsp;<input type="submit" value="'.get_string('search').'" /></div></form>'."\n";
788 $perpageurl = clone($baseurl);
789 $perpageurl->remove_params('perpage');
790 if ($perpage == SHOW_ALL_PAGE_SIZE) {
791 $perpageurl->param('perpage', DEFAULT_PAGE_SIZE);
792 echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showperpage', '', DEFAULT_PAGE_SIZE)), array(), 'showall');
794 } else if ($matchcount > 0 && $perpage < $matchcount) {
795 $perpageurl->param('perpage', SHOW_ALL_PAGE_SIZE);
796 echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showall', '', $matchcount)), array(), 'showall');
799 echo '</div>'; // userlist
801 echo $OUTPUT->footer();
803 if ($userlist) {
804 $userlist->close();
808 function get_course_lastaccess_sql($accesssince='') {
809 if (empty($accesssince)) {
810 return '';
812 if ($accesssince == -1) { // never
813 return 'ul.timeaccess = 0';
814 } else {
815 return 'ul.timeaccess != 0 AND ul.timeaccess < '.$accesssince;
819 function get_user_lastaccess_sql($accesssince='') {
820 if (empty($accesssince)) {
821 return '';
823 if ($accesssince == -1) { // never
824 return 'u.lastaccess = 0';
825 } else {
826 return 'u.lastaccess != 0 AND u.lastaccess < '.$accesssince;
830 function get_participants_extra ($userids, $course, $context) {
831 global $CFG, $DB;
833 if (count($userids) === 0) {
834 return array();
837 $params = array();
839 $userids = implode(',', $userids);
841 // turn the path into a list of context ids
842 $contextids = substr($context->path, 1); // kill leading slash
843 $contextids = str_replace('/', ',', $contextids);;
845 $gpjoin = "LEFT OUTER JOIN {groupings_groups} gpg
846 ON gpg.groupid=g.id
847 LEFT OUTER JOIN {groupings} gp
848 ON (gp.courseid={$course->id} AND gp.id=gpg.groupingid)";
849 $gpselect = ',gp.id AS gpid, gp.name AS gpname ';
851 // Note: this returns strange redundant rows, perhaps
852 // due to the multiple OUTER JOINs. If we can tweak the
853 // JOINs to avoid it ot
854 $sql = "SELECT DISTINCT ra.userid,
855 ctx.id AS ctxid, ctx.path AS ctxpath, ctx.depth AS ctxdepth,
856 ctx.contextlevel AS ctxlevel, ctx.instanceid AS ctxinstanceid,
857 cc.name AS ccname,
858 ra.roleid AS roleid,
859 g.id AS gid, g.name AS gname
860 $gpselect
861 FROM {role_assignments} ra
862 JOIN {context} ctx
863 ON (ra.contextid=ctx.id)
864 LEFT JOIN {course_categories} cc
865 ON (ctx.contextlevel=40 AND ctx.instanceid=cc.id)
867 /* only if groups active */
868 LEFT JOIN {groups_members} gm
869 ON (ra.userid=gm.userid)
870 LEFT JOIN {groups} g
871 ON (gm.groupid=g.id AND g.courseid={$course->id})
872 /* and if groupings is enabled... */
873 $gpjoin
875 WHERE ra.userid IN ( $userids )
876 AND ra.contextid in ( $contextids )
878 ORDER BY ra.userid, ctx.depth DESC";
880 $rs = $DB->get_recordset_sql($sql, $params);
881 $extra = array();
883 // Data structure -
884 // $extra [ $userid ] [ 'group' ] [ $groupid => 'group name']
885 // [ 'gping' ] [ $gpingid => 'gping name']
886 // [ 'ra' ] [ [ "$ctxid:$roleid" => [ctxid => $ctxid
887 // ctxdepth => $ctxdepth,
888 // ctxpath => $ctxpath,
889 // ctxname => 'name' (categories only)
890 // ctxinstid =>
891 // roleid => $roleid
893 foreach ($rs as $rec) {
894 $userid = $rec->userid;
896 // Prime an initial user rec...
897 if (!isset($extra[$userid])) {
898 $extra[$userid] = array( 'group' => array(),
899 'gping' => array(),
900 'ra' => array() );
903 if (!empty($rec->gid)) {
904 $extra[$userid]['group'][$rec->gid]= $rec->gname;
906 if (!empty($rec->gpid)) {
907 $extra[$userid]['gping'][$rec->gpid]= $rec->gpname;
909 $rakey = $rec->ctxid . ':' . $rec->roleid;
910 if (!isset($extra[$userid]['ra'][$rakey])) {
911 $extra[$userid]['ra'][$rakey] = array('ctxid' => $rec->ctxid,
912 'ctxlevel' => $rec->ctxlevel,
913 'ctxinstanceid' => $rec->ctxinstanceid,
914 'ccname' => $rec->ccname,
915 'roleid' => $rec->roleid);
919 $rs->close();
920 return $extra;