Commit | Line | Data |
---|---|---|
aa6c1ced | 1 | <?php |
a2ed6e69 SH |
2 | // This file is part of Moodle - http://moodle.org/ |
3 | // | |
4 | // Moodle is free software: you can redistribute it and/or modify | |
5 | // it under the terms of the GNU General Public License as published by | |
6 | // the Free Software Foundation, either version 3 of the License, or | |
7 | // (at your option) any later version. | |
8 | // | |
9 | // Moodle is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | // | |
14 | // You should have received a copy of the GNU General Public License | |
15 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
16 | ||
17 | /** | |
18 | * Lists all the users within a given course. | |
19 | * | |
20 | * @copyright 1999 Martin Dougiamas http://dougiamas.com | |
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
22 | * @package core_user | |
23 | */ | |
24 | ||
25 | require_once('../config.php'); | |
0ff203b6 | 26 | require_once($CFG->dirroot.'/user/lib.php'); |
a2ed6e69 SH |
27 | require_once($CFG->libdir.'/tablelib.php'); |
28 | require_once($CFG->libdir.'/filelib.php'); | |
29 | ||
30 | define('USER_SMALL_CLASS', 20); // Below this is considered small. | |
31 | define('USER_LARGE_CLASS', 200); // Above this is considered large. | |
32 | define('DEFAULT_PAGE_SIZE', 20); | |
33 | define('SHOW_ALL_PAGE_SIZE', 5000); | |
a2ed6e69 SH |
34 | |
35 | $page = optional_param('page', 0, PARAM_INT); // Which page to show. | |
36 | $perpage = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT); // How many per page. | |
a2ed6e69 SH |
37 | $accesssince = optional_param('accesssince', 0, PARAM_INT); // Filter by last access. -1 = never. |
38 | $search = optional_param('search', '', PARAM_RAW); // Make sure it is processed with p() or s() when sending to output! | |
39 | $roleid = optional_param('roleid', 0, PARAM_INT); // Optional roleid, 0 means all enrolled users (or all on the frontpage). | |
40 | $contextid = optional_param('contextid', 0, PARAM_INT); // One of this or. | |
41 | $courseid = optional_param('id', 0, PARAM_INT); // This are required. | |
5b7c500a | 42 | $selectall = optional_param('selectall', false, PARAM_BOOL); // When rendering checkboxes against users mark them all checked. |
a2ed6e69 SH |
43 | |
44 | $PAGE->set_url('/user/index.php', array( | |
45 | 'page' => $page, | |
46 | 'perpage' => $perpage, | |
a2ed6e69 SH |
47 | 'accesssince' => $accesssince, |
48 | 'search' => $search, | |
49 | 'roleid' => $roleid, | |
50 | 'contextid' => $contextid, | |
51 | 'id' => $courseid)); | |
52 | ||
53 | if ($contextid) { | |
54 | $context = context::instance_by_id($contextid, MUST_EXIST); | |
55 | if ($context->contextlevel != CONTEXT_COURSE) { | |
56 | print_error('invalidcontext'); | |
57 | } | |
58 | $course = $DB->get_record('course', array('id' => $context->instanceid), '*', MUST_EXIST); | |
59 | } else { | |
60 | $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); | |
61 | $context = context_course::instance($course->id, MUST_EXIST); | |
62 | } | |
63 | // Not needed anymore. | |
64 | unset($contextid); | |
65 | unset($courseid); | |
f9903ed0 | 66 | |
a2ed6e69 | 67 | require_login($course); |
f9903ed0 | 68 | |
a2ed6e69 SH |
69 | $systemcontext = context_system::instance(); |
70 | $isfrontpage = ($course->id == SITEID); | |
f9903ed0 | 71 | |
a2ed6e69 | 72 | $frontpagectx = context_course::instance(SITEID); |
4f0c2d00 | 73 | |
a2ed6e69 SH |
74 | if ($isfrontpage) { |
75 | $PAGE->set_pagelayout('admin'); | |
76 | require_capability('moodle/site:viewparticipants', $systemcontext); | |
77 | } else { | |
78 | $PAGE->set_pagelayout('incourse'); | |
79 | require_capability('moodle/course:viewparticipants', $context); | |
80 | } | |
224aa44a | 81 | |
a2ed6e69 | 82 | $rolenamesurl = new moodle_url("$CFG->wwwroot/user/index.php?contextid=$context->id&sifirst=&silast="); |
6d3c57f4 | 83 | |
a2ed6e69 SH |
84 | $rolenames = role_fix_names(get_profile_roles($context), $context, ROLENAME_ALIAS, true); |
85 | if ($isfrontpage) { | |
86 | $rolenames[0] = get_string('allsiteusers', 'role'); | |
87 | } else { | |
88 | $rolenames[0] = get_string('allparticipants'); | |
89 | } | |
d7270311 | 90 | |
a2ed6e69 SH |
91 | // Make sure other roles may not be selected by any means. |
92 | if (empty($rolenames[$roleid])) { | |
93 | print_error('noparticipants'); | |
94 | } | |
5f9e296a | 95 | |
a2ed6e69 SH |
96 | // No roles to display yet? |
97 | // frontpage course is an exception, on the front page course we should display all users. | |
98 | if (empty($rolenames) && !$isfrontpage) { | |
99 | if (has_capability('moodle/role:assign', $context)) { | |
100 | redirect($CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id); | |
101 | } else { | |
4f0c2d00 | 102 | print_error('noparticipants'); |
5f9e296a | 103 | } |
a2ed6e69 | 104 | } |
5f9e296a | 105 | |
0ff203b6 JL |
106 | // Trigger events. |
107 | user_list_view($course, $context); | |
a2ed6e69 SH |
108 | |
109 | $bulkoperations = has_capability('moodle/course:bulkmessaging', $context); | |
110 | ||
111 | $countries = get_string_manager()->get_list_of_countries(); | |
112 | ||
113 | $strnever = get_string('never'); | |
114 | ||
115 | $datestring = new stdClass(); | |
116 | $datestring->year = get_string('year'); | |
117 | $datestring->years = get_string('years'); | |
118 | $datestring->day = get_string('day'); | |
119 | $datestring->days = get_string('days'); | |
120 | $datestring->hour = get_string('hour'); | |
121 | $datestring->hours = get_string('hours'); | |
122 | $datestring->min = get_string('min'); | |
123 | $datestring->mins = get_string('mins'); | |
124 | $datestring->sec = get_string('sec'); | |
125 | $datestring->secs = get_string('secs'); | |
126 | ||
a2ed6e69 SH |
127 | // Check to see if groups are being used in this course |
128 | // and if so, set $currentgroup to reflect the current group. | |
ff3caf30 | 129 | |
a2ed6e69 SH |
130 | $groupmode = groups_get_course_groupmode($course); // Groups are being used. |
131 | $currentgroup = groups_get_course_group($course, true); | |
ff3caf30 | 132 | |
a2ed6e69 SH |
133 | if (!$currentgroup) { // To make some other functions work better later. |
134 | $currentgroup = null; | |
135 | } | |
ff3caf30 | 136 | |
a2ed6e69 | 137 | $isseparategroups = ($course->groupmode == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $context)); |
ff3caf30 | 138 | |
a2ed6e69 SH |
139 | $PAGE->set_title("$course->shortname: ".get_string('participants')); |
140 | $PAGE->set_heading($course->fullname); | |
141 | $PAGE->set_pagetype('course-view-' . $course->format); | |
142 | $PAGE->add_body_class('path-user'); // So we can style it independently. | |
143 | $PAGE->set_other_editing_capability('moodle/course:manageactivities'); | |
2cb2ce61 | 144 | |
a2ed6e69 | 145 | echo $OUTPUT->header(); |
4e1f6047 | 146 | echo $OUTPUT->heading(get_string('participants')); |
caa8363f | 147 | |
a2ed6e69 | 148 | echo '<div class="userlist">'; |
0be6f678 | 149 | |
a2ed6e69 SH |
150 | if ($isseparategroups and (!$currentgroup) ) { |
151 | // The user is not in the group so show message and exit. | |
152 | echo $OUTPUT->heading(get_string("notingroup")); | |
153 | echo $OUTPUT->footer(); | |
154 | exit; | |
155 | } | |
99cca847 | 156 | |
ff3caf30 | 157 | |
a2ed6e69 SH |
158 | // Should use this variable so that we don't break stuff every time a variable is added or changed. |
159 | $baseurl = new moodle_url('/user/index.php', array( | |
160 | 'contextid' => $context->id, | |
161 | 'roleid' => $roleid, | |
162 | 'id' => $course->id, | |
163 | 'perpage' => $perpage, | |
164 | 'accesssince' => $accesssince, | |
165 | 'search' => s($search))); | |
166 | ||
167 | // Setting up tags. | |
168 | if ($course->id == SITEID) { | |
169 | $filtertype = 'site'; | |
170 | } else if ($course->id && !$currentgroup) { | |
171 | $filtertype = 'course'; | |
172 | $filterselect = $course->id; | |
173 | } else { | |
174 | $filtertype = 'group'; | |
175 | $filterselect = $currentgroup; | |
176 | } | |
03d9401e | 177 | |
1242eb8f | 178 | |
03d9401e | 179 | |
a2ed6e69 SH |
180 | // Get the hidden field list. |
181 | if (has_capability('moodle/course:viewhiddenuserfields', $context)) { | |
182 | $hiddenfields = array(); // Teachers and admins are allowed to see everything. | |
183 | } else { | |
c6b44cb4 | 184 | $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields)); |
a2ed6e69 | 185 | } |
1242eb8f | 186 | |
a2ed6e69 SH |
187 | if (isset($hiddenfields['lastaccess'])) { |
188 | // Do not allow access since filtering. | |
189 | $accesssince = 0; | |
190 | } | |
3468d58a | 191 | |
a2ed6e69 SH |
192 | // Print settings and things in a table across the top. |
193 | $controlstable = new html_table(); | |
194 | $controlstable->attributes['class'] = 'controls'; | |
195 | $controlstable->cellspacing = 0; | |
196 | $controlstable->data[] = new html_table_row(); | |
197 | ||
24c3db91 DP |
198 | if ($groupmenu = groups_print_course_menu($course, $baseurl->out(), true)) { |
199 | $controlstable->data[0]->cells[] = $groupmenu; | |
200 | } | |
a2ed6e69 SH |
201 | |
202 | if (!isset($hiddenfields['lastaccess'])) { | |
203 | // Get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far. | |
204 | // We need to make it diferently for normal courses and site course. | |
205 | if (!$isfrontpage) { | |
206 | $minlastaccess = $DB->get_field_sql('SELECT min(timeaccess) | |
207 | FROM {user_lastaccess} | |
208 | WHERE courseid = ? | |
209 | AND timeaccess != 0', array($course->id)); | |
210 | $lastaccess0exists = $DB->record_exists('user_lastaccess', array('courseid' => $course->id, 'timeaccess' => 0)); | |
211 | } else { | |
212 | $minlastaccess = $DB->get_field_sql('SELECT min(lastaccess) | |
213 | FROM {user} | |
214 | WHERE lastaccess != 0'); | |
215 | $lastaccess0exists = $DB->record_exists('user', array('lastaccess' => 0)); | |
7da0af9f | 216 | } |
87a13824 | 217 | |
a2ed6e69 SH |
218 | $now = usergetmidnight(time()); |
219 | $timeaccess = array(); | |
220 | $baseurl->remove_params('accesssince'); | |
87a13824 | 221 | |
a2ed6e69 SH |
222 | // Makes sense for this to go first. |
223 | $timeoptions[0] = get_string('selectperiod'); | |
87a13824 | 224 | |
a2ed6e69 SH |
225 | // Days. |
226 | for ($i = 1; $i < 7; $i++) { | |
227 | if (strtotime('-'.$i.' days', $now) >= $minlastaccess) { | |
228 | $timeoptions[strtotime('-'.$i.' days', $now)] = get_string('numdays', 'moodle', $i); | |
ca792680 | 229 | } |
a2ed6e69 SH |
230 | } |
231 | // Weeks. | |
232 | for ($i = 1; $i < 10; $i++) { | |
233 | if (strtotime('-'.$i.' weeks', $now) >= $minlastaccess) { | |
234 | $timeoptions[strtotime('-'.$i.' weeks', $now)] = get_string('numweeks', 'moodle', $i); | |
5ff311f0 | 235 | } |
a2ed6e69 SH |
236 | } |
237 | // Months. | |
238 | for ($i = 2; $i < 12; $i++) { | |
239 | if (strtotime('-'.$i.' months', $now) >= $minlastaccess) { | |
240 | $timeoptions[strtotime('-'.$i.' months', $now)] = get_string('nummonths', 'moodle', $i); | |
31b71336 | 241 | } |
a2ed6e69 SH |
242 | } |
243 | // Try a year. | |
244 | if (strtotime('-1 year', $now) >= $minlastaccess) { | |
245 | $timeoptions[strtotime('-1 year', $now)] = get_string('lastyear'); | |
246 | } | |
87a13824 | 247 | |
a2ed6e69 SH |
248 | if (!empty($lastaccess0exists)) { |
249 | $timeoptions[-1] = get_string('never'); | |
250 | } | |
87a13824 | 251 | |
a2ed6e69 SH |
252 | if (count($timeoptions) > 1) { |
253 | $select = new single_select($baseurl, 'accesssince', $timeoptions, $accesssince, null, 'timeoptions'); | |
254 | $select->set_label(get_string('usersnoaccesssince')); | |
255 | $controlstable->data[0]->cells[] = $OUTPUT->render($select); | |
77c645df | 256 | } |
a2ed6e69 | 257 | } |
87a13824 | 258 | |
a2ed6e69 SH |
259 | echo html_writer::table($controlstable); |
260 | ||
261 | if ($currentgroup and (!$isseparategroups or has_capability('moodle/site:accessallgroups', $context))) { | |
262 | // Display info about the group. | |
263 | if ($group = groups_get_group($currentgroup)) { | |
264 | if (!empty($group->description) or (!empty($group->picture) and empty($group->hidepicture))) { | |
265 | $groupinfotable = new html_table(); | |
266 | $groupinfotable->attributes['class'] = 'groupinfobox'; | |
267 | $picturecell = new html_table_cell(); | |
268 | $picturecell->attributes['class'] = 'left side picture'; | |
269 | $picturecell->text = print_group_picture($group, $course->id, true, true, false); | |
270 | ||
271 | $contentcell = new html_table_cell(); | |
272 | $contentcell->attributes['class'] = 'content'; | |
273 | ||
274 | $contentheading = $group->name; | |
275 | if (has_capability('moodle/course:managegroups', $context)) { | |
276 | $aurl = new moodle_url('/group/group.php', array('id' => $group->id, 'courseid' => $group->courseid)); | |
277 | $contentheading .= ' ' . $OUTPUT->action_icon($aurl, new pix_icon('t/edit', get_string('editgroupprofile'))); | |
278 | } | |
8bdc9cac | 279 | |
a2ed6e69 SH |
280 | $group->description = file_rewrite_pluginfile_urls($group->description, 'pluginfile.php', $context->id, 'group', |
281 | 'description', $group->id); | |
282 | if (!isset($group->descriptionformat)) { | |
283 | $group->descriptionformat = FORMAT_MOODLE; | |
ff3caf30 | 284 | } |
a2ed6e69 SH |
285 | $options = array('overflowdiv' => true); |
286 | $formatteddesc = format_text($group->description, $group->descriptionformat, $options); | |
287 | $contentcell->text = $OUTPUT->heading($contentheading, 3) . $formatteddesc; | |
288 | $groupinfotable->data[] = new html_table_row(array($picturecell, $contentcell)); | |
289 | echo html_writer::table($groupinfotable); | |
ff3caf30 | 290 | } |
291 | } | |
a2ed6e69 | 292 | } |
ff3caf30 | 293 | |
a2ed6e69 SH |
294 | // Define a table showing a list of users in the current role selection. |
295 | $tablecolumns = array(); | |
296 | $tableheaders = array(); | |
4c7593ff | 297 | if ($bulkoperations) { |
a2ed6e69 SH |
298 | $tablecolumns[] = 'select'; |
299 | $tableheaders[] = get_string('select'); | |
300 | } | |
301 | $tablecolumns[] = 'userpic'; | |
302 | $tablecolumns[] = 'fullname'; | |
c238e1e2 | 303 | |
a2ed6e69 SH |
304 | $extrafields = get_extra_user_fields($context); |
305 | $tableheaders[] = get_string('userpic'); | |
306 | $tableheaders[] = get_string('fullnameuser'); | |
77c645df | 307 | |
4c7593ff MN |
308 | |
309 | foreach ($extrafields as $field) { | |
310 | $tablecolumns[] = $field; | |
311 | $tableheaders[] = get_user_field_name($field); | |
a2ed6e69 | 312 | } |
4c7593ff | 313 | if (!isset($hiddenfields['city'])) { |
a2ed6e69 SH |
314 | $tablecolumns[] = 'city'; |
315 | $tableheaders[] = get_string('city'); | |
316 | } | |
4c7593ff | 317 | if (!isset($hiddenfields['country'])) { |
a2ed6e69 SH |
318 | $tablecolumns[] = 'country'; |
319 | $tableheaders[] = get_string('country'); | |
320 | } | |
321 | if (!isset($hiddenfields['lastaccess'])) { | |
322 | $tablecolumns[] = 'lastaccess'; | |
e89682d8 DC |
323 | if ($course->id == SITEID) { |
324 | // Exception case for viewing participants on site home. | |
325 | $tableheaders[] = get_string('lastsiteaccess'); | |
326 | } else { | |
327 | $tableheaders[] = get_string('lastcourseaccess'); | |
328 | } | |
a2ed6e69 | 329 | } |
77c645df | 330 | |
a2ed6e69 SH |
331 | $table = new flexible_table('user-index-participants-'.$course->id); |
332 | $table->define_columns($tablecolumns); | |
333 | $table->define_headers($tableheaders); | |
334 | $table->define_baseurl($baseurl->out()); | |
5ff311f0 | 335 | |
28d27e85 | 336 | if (!isset($hiddenfields['lastaccess'])) { |
337 | $table->sortable(true, 'lastaccess', SORT_DESC); | |
a2ed6e69 SH |
338 | } else { |
339 | $table->sortable(true, 'firstname', SORT_ASC); | |
340 | } | |
4f0c2d00 | 341 | |
a2ed6e69 SH |
342 | $table->no_sorting('roles'); |
343 | $table->no_sorting('groups'); | |
344 | $table->no_sorting('groupings'); | |
345 | $table->no_sorting('select'); | |
346 | ||
347 | $table->set_attribute('cellspacing', '0'); | |
348 | $table->set_attribute('id', 'participants'); | |
349 | $table->set_attribute('class', 'generaltable generalbox'); | |
350 | ||
351 | $table->set_control_variables(array( | |
352 | TABLE_VAR_SORT => 'ssort', | |
353 | TABLE_VAR_HIDE => 'shide', | |
354 | TABLE_VAR_SHOW => 'sshow', | |
355 | TABLE_VAR_IFIRST => 'sifirst', | |
356 | TABLE_VAR_ILAST => 'silast', | |
357 | TABLE_VAR_PAGE => 'spage' | |
358 | )); | |
359 | $table->setup(); | |
360 | ||
361 | list($esql, $params) = get_enrolled_sql($context, null, $currentgroup, true); | |
362 | $joins = array("FROM {user} u"); | |
363 | $wheres = array(); | |
364 | ||
368f0bf8 DC |
365 | $userfields = array('username', 'email', 'city', 'country', 'lang', 'timezone', 'maildisplay'); |
366 | $mainuserfields = user_picture::fields('u', $userfields); | |
367 | $extrasql = get_extra_user_fields_sql($context, 'u', '', $userfields); | |
a2ed6e69 SH |
368 | |
369 | if ($isfrontpage) { | |
370 | $select = "SELECT $mainuserfields, u.lastaccess$extrasql"; | |
371 | $joins[] = "JOIN ($esql) e ON e.id = u.id"; // Everybody on the frontpage usually. | |
372 | if ($accesssince) { | |
373 | $wheres[] = get_user_lastaccess_sql($accesssince); | |
374 | } | |
375 | ||
376 | } else { | |
377 | $select = "SELECT $mainuserfields, COALESCE(ul.timeaccess, 0) AS lastaccess$extrasql"; | |
378 | $joins[] = "JOIN ($esql) e ON e.id = u.id"; // Course enrolled users only. | |
379 | $joins[] = "LEFT JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = :courseid)"; // Not everybody accessed course yet. | |
380 | $params['courseid'] = $course->id; | |
381 | if ($accesssince) { | |
382 | $wheres[] = get_course_lastaccess_sql($accesssince); | |
165088f6 | 383 | } |
a2ed6e69 | 384 | } |
5f9e296a | 385 | |
a2ed6e69 SH |
386 | // Performance hacks - we preload user contexts together with accounts. |
387 | $ccselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); | |
388 | $ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)"; | |
389 | $params['contextlevel'] = CONTEXT_USER; | |
390 | $select .= $ccselect; | |
391 | $joins[] = $ccjoin; | |
c0527567 | 392 | |
4f0c2d00 | 393 | |
a2ed6e69 SH |
394 | // Limit list to users with some role only. |
395 | if ($roleid) { | |
419d1abd DW |
396 | // We want to query both the current context and parent contexts. |
397 | list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'relatedctx'); | |
398 | ||
a2ed6e69 | 399 | $wheres[] = "u.id IN (SELECT userid FROM {role_assignments} WHERE roleid = :roleid AND contextid $relatedctxsql)"; |
419d1abd | 400 | $params = array_merge($params, array('roleid' => $roleid), $relatedctxparams); |
a2ed6e69 | 401 | } |
0be6f678 | 402 | |
a2ed6e69 SH |
403 | $from = implode("\n", $joins); |
404 | if ($wheres) { | |
405 | $where = "WHERE " . implode(" AND ", $wheres); | |
406 | } else { | |
407 | $where = ""; | |
408 | } | |
4f0c2d00 | 409 | |
a2ed6e69 | 410 | $totalcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params); |
77c645df | 411 | |
a2ed6e69 SH |
412 | if (!empty($search)) { |
413 | $fullname = $DB->sql_fullname('u.firstname', 'u.lastname'); | |
414 | $wheres[] = "(". $DB->sql_like($fullname, ':search1', false, false) . | |
415 | " OR ". $DB->sql_like('email', ':search2', false, false) . | |
416 | " OR ". $DB->sql_like('idnumber', ':search3', false, false) .") "; | |
417 | $params['search1'] = "%$search%"; | |
418 | $params['search2'] = "%$search%"; | |
419 | $params['search3'] = "%$search%"; | |
420 | } | |
77c645df | 421 | |
a2ed6e69 SH |
422 | list($twhere, $tparams) = $table->get_sql_where(); |
423 | if ($twhere) { | |
424 | $wheres[] = $twhere; | |
425 | $params = array_merge($params, $tparams); | |
426 | } | |
77c645df | 427 | |
a2ed6e69 SH |
428 | $from = implode("\n", $joins); |
429 | if ($wheres) { | |
430 | $where = "WHERE " . implode(" AND ", $wheres); | |
431 | } else { | |
432 | $where = ""; | |
433 | } | |
77c645df | 434 | |
a2ed6e69 SH |
435 | if ($table->get_sql_sort()) { |
436 | $sort = ' ORDER BY '.$table->get_sql_sort(); | |
437 | } else { | |
438 | $sort = ''; | |
439 | } | |
77c645df | 440 | |
a2ed6e69 | 441 | $matchcount = $DB->count_records_sql("SELECT COUNT(u.id) $from $where", $params); |
77c645df | 442 | |
a2ed6e69 SH |
443 | $table->initialbars(true); |
444 | $table->pagesize($perpage, $matchcount); | |
77c645df | 445 | |
a2ed6e69 SH |
446 | // List of users at the current visible page - paging makes it relatively short. |
447 | $userlist = $DB->get_recordset_sql("$select $from $where $sort", $params, $table->get_page_start(), $table->get_page_size()); | |
3e219038 | 448 | |
a2ed6e69 SH |
449 | // If there are multiple Roles in the course, then show a drop down menu for switching. |
450 | if (count($rolenames) > 1) { | |
451 | echo '<div class="rolesform">'; | |
32bd11cb BB |
452 | echo $OUTPUT->single_select($rolenamesurl, 'roleid', $rolenames, $roleid, null, |
453 | 'rolesform', array('label' => get_string('currentrole', 'role'))); | |
a2ed6e69 | 454 | echo '</div>'; |
5f9e296a | 455 | |
a2ed6e69 SH |
456 | } else if (count($rolenames) == 1) { |
457 | // When all users with the same role - print its name. | |
458 | echo '<div class="rolesform">'; | |
459 | echo get_string('role').get_string('labelsep', 'langconfig'); | |
460 | $rolename = reset($rolenames); | |
461 | echo $rolename; | |
462 | echo '</div>'; | |
463 | } | |
3e219038 | 464 | |
7057c3ef DP |
465 | $editlink = ''; |
466 | if ($course->id != SITEID && has_capability('moodle/course:enrolreview', $context)) { | |
467 | $editlink = new moodle_url('/enrol/users.php', array('id' => $course->id)); | |
468 | } | |
469 | ||
a2ed6e69 SH |
470 | if ($roleid > 0) { |
471 | $a = new stdClass(); | |
472 | $a->number = $totalcount; | |
473 | $a->role = $rolenames[$roleid]; | |
474 | $heading = format_string(get_string('xuserswiththerole', 'role', $a)); | |
f642a21a | 475 | |
9488b6f3 | 476 | if ($currentgroup and !empty($group)) { |
a2ed6e69 SH |
477 | $a->group = $group->name; |
478 | $heading .= ' ' . format_string(get_string('ingroup', 'role', $a)); | |
479 | } | |
f642a21a | 480 | |
9488b6f3 | 481 | if ($accesssince && !empty($timeoptions[$accesssince])) { |
a2ed6e69 SH |
482 | $a->timeperiod = $timeoptions[$accesssince]; |
483 | $heading .= ' ' . format_string(get_string('inactiveformorethan', 'role', $a)); | |
484 | } | |
f642a21a | 485 | |
a2ed6e69 | 486 | $heading .= ": $a->number"; |
b85b25eb | 487 | |
7057c3ef DP |
488 | if (!empty($editlink)) { |
489 | $editlink->param('role', $roleid); | |
490 | $heading .= $OUTPUT->action_icon($editlink, new pix_icon('t/edit', get_string('edit'))); | |
a2ed6e69 SH |
491 | } |
492 | echo $OUTPUT->heading($heading, 3); | |
493 | } else { | |
a2ed6e69 SH |
494 | if ($course->id == SITEID and $roleid < 0) { |
495 | $strallparticipants = get_string('allsiteusers', 'role'); | |
496 | } else { | |
497 | $strallparticipants = get_string('allparticipants'); | |
498 | } | |
7057c3ef DP |
499 | |
500 | if (!empty($editlink)) { | |
501 | $editlink = $OUTPUT->action_icon($editlink, new pix_icon('t/edit', get_string('edit'))); | |
502 | } | |
503 | ||
a2ed6e69 SH |
504 | if ($matchcount < $totalcount) { |
505 | echo $OUTPUT->heading($strallparticipants.get_string('labelsep', 'langconfig').$matchcount.'/'.$totalcount . $editlink, 3); | |
506 | } else { | |
507 | echo $OUTPUT->heading($strallparticipants.get_string('labelsep', 'langconfig').$matchcount . $editlink, 3); | |
508 | } | |
509 | } | |
3e219038 | 510 | |
77c645df | 511 | |
a2ed6e69 SH |
512 | if ($bulkoperations) { |
513 | echo '<form action="action_redir.php" method="post" id="participantsform">'; | |
514 | echo '<div>'; | |
515 | echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />'; | |
516 | echo '<input type="hidden" name="returnto" value="'.s($PAGE->url->out(false)).'" />'; | |
517 | } | |
77c645df | 518 | |
4c7593ff MN |
519 | $countrysort = (strpos($sort, 'country') !== false); |
520 | $timeformat = get_string('strftimedate'); | |
77c645df | 521 | |
4c7593ff | 522 | if ($userlist) { |
77c645df | 523 | |
4c7593ff MN |
524 | $usersprinted = array(); |
525 | foreach ($userlist as $user) { | |
526 | if (in_array($user->id, $usersprinted)) { // Prevent duplicates by r.hidden - MDL-13935. | |
527 | continue; | |
a2ed6e69 | 528 | } |
4c7593ff | 529 | $usersprinted[] = $user->id; // Add new user to the array of users printed. |
a2ed6e69 | 530 | |
4c7593ff | 531 | context_helper::preload_from_record($user); |
a2ed6e69 | 532 | |
4c7593ff MN |
533 | if ($user->lastaccess) { |
534 | $lastaccess = format_time(time() - $user->lastaccess, $datestring); | |
a2ed6e69 | 535 | } else { |
4c7593ff | 536 | $lastaccess = $strnever; |
ee4a52c5 | 537 | } |
3997cb40 | 538 | |
4c7593ff MN |
539 | if (empty($user->country)) { |
540 | $country = ''; | |
3997cb40 | 541 | |
4c7593ff MN |
542 | } else { |
543 | if ($countrysort) { | |
544 | $country = '('.$user->country.') '.$countries[$user->country]; | |
a2ed6e69 | 545 | } else { |
4c7593ff | 546 | $country = $countries[$user->country]; |
a2ed6e69 | 547 | } |
4c7593ff | 548 | } |
77c645df | 549 | |
4c7593ff | 550 | $usercontext = context_user::instance($user->id); |
77c645df | 551 | |
4c7593ff MN |
552 | if ($piclink = ($USER->id == $user->id || has_capability('moodle/user:viewdetails', $context) || has_capability('moodle/user:viewdetails', $usercontext))) { |
553 | $profilelink = '<strong><a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&course='.$course->id.'">'.fullname($user).'</a></strong>'; | |
554 | } else { | |
555 | $profilelink = '<strong>'.fullname($user).'</strong>'; | |
556 | } | |
0be6f678 | 557 | |
4c7593ff MN |
558 | $data = array(); |
559 | if ($bulkoperations) { | |
560 | if ($selectall) { | |
561 | $checked = 'checked="true"'; | |
a2ed6e69 | 562 | } else { |
4c7593ff | 563 | $checked = ''; |
a2ed6e69 | 564 | } |
4c7593ff MN |
565 | $data[] = '<input type="checkbox" class="usercheckbox" name="user'.$user->id.'" ' . $checked .'/>'; |
566 | } | |
567 | $data[] = $OUTPUT->user_picture($user, array('size' => 35, 'courseid' => $course->id)); | |
568 | $data[] = $profilelink; | |
664fe87f | 569 | |
4c7593ff MN |
570 | foreach ($extrafields as $field) { |
571 | $data[] = $user->{$field}; | |
eca3af25 | 572 | } |
576ad290 | 573 | |
4c7593ff MN |
574 | if (!isset($hiddenfields['city'])) { |
575 | $data[] = $user->city; | |
576 | } | |
577 | if (!isset($hiddenfields['country'])) { | |
578 | $data[] = $country; | |
579 | } | |
580 | if (!isset($hiddenfields['lastaccess'])) { | |
581 | $data[] = $lastaccess; | |
582 | } | |
d88c5043 | 583 | |
4c7593ff MN |
584 | $table->add_data($data); |
585 | } | |
a2ed6e69 | 586 | } |
b90e2f19 | 587 | |
4c7593ff MN |
588 | $table->print_html(); |
589 | ||
8dd42b38 AH |
590 | $perpageurl = clone($baseurl); |
591 | $perpageurl->remove_params('perpage'); | |
592 | if ($perpage == SHOW_ALL_PAGE_SIZE) { | |
593 | $perpageurl->param('perpage', DEFAULT_PAGE_SIZE); | |
594 | echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showperpage', '', DEFAULT_PAGE_SIZE)), array(), 'showall'); | |
595 | ||
596 | } else if ($matchcount > 0 && $perpage < $matchcount) { | |
597 | $perpageurl->param('perpage', SHOW_ALL_PAGE_SIZE); | |
598 | echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showall', '', $matchcount)), array(), 'showall'); | |
599 | } | |
600 | ||
a2ed6e69 SH |
601 | if ($bulkoperations) { |
602 | echo '<br /><div class="buttons">'; | |
5b7c500a AH |
603 | |
604 | if ($matchcount > 0 && $perpage < $matchcount) { | |
605 | $perpageurl = clone($baseurl); | |
606 | $perpageurl->remove_params('perpage'); | |
607 | $perpageurl->param('perpage', SHOW_ALL_PAGE_SIZE); | |
608 | $perpageurl->param('selectall', true); | |
609 | $showalllink = $perpageurl; | |
610 | } else { | |
611 | $showalllink = false; | |
612 | } | |
613 | ||
b27c8d81 | 614 | echo html_writer::start_tag('div', array('class' => 'btn-group')); |
5b7c500a AH |
615 | if ($perpage < $matchcount) { |
616 | // Select all users, refresh page showing all users and mark them all selected. | |
617 | $label = get_string('selectalluserswithcount', 'moodle', $matchcount); | |
b27c8d81 SB |
618 | echo html_writer::tag('input', "", array('type' => 'button', 'id' => 'checkall', 'class' => 'btn btn-secondary', |
619 | 'value' => $label, 'data-showallink' => $showalllink)); | |
5b7c500a | 620 | // Select all users, mark all users on page as selected. |
b27c8d81 SB |
621 | echo html_writer::tag('input', "", array('type' => 'button', 'id' => 'checkallonpage', 'class' => 'btn btn-secondary', |
622 | 'value' => get_string('selectallusersonpage'))); | |
5b7c500a | 623 | } else { |
b27c8d81 SB |
624 | echo html_writer::tag('input', "", array('type' => 'button', 'id' => 'checkallonpage', 'class' => 'btn btn-secondary', |
625 | 'value' => get_string('selectall'))); | |
5b7c500a AH |
626 | } |
627 | ||
b27c8d81 SB |
628 | echo html_writer::tag('input', "", array('type' => 'button', 'id' => 'checknone', 'class' => 'btn btn-secondary', |
629 | 'value' => get_string('deselectall'))); | |
630 | echo html_writer::end_tag('div'); | |
a2ed6e69 SH |
631 | $displaylist = array(); |
632 | $displaylist['messageselect.php'] = get_string('messageselectadd'); | |
633 | if (!empty($CFG->enablenotes) && has_capability('moodle/notes:manage', $context) && $context->id != $frontpagectx->id) { | |
634 | $displaylist['addnote.php'] = get_string('addnewnote', 'notes'); | |
635 | $displaylist['groupaddnote.php'] = get_string('groupaddnewnote', 'notes'); | |
636 | } | |
637 | ||
638 | echo $OUTPUT->help_icon('withselectedusers'); | |
639 | echo html_writer::tag('label', get_string("withselectedusers"), array('for' => 'formactionid')); | |
640 | echo html_writer::select($displaylist, 'formaction', '', array('' => 'choosedots'), array('id' => 'formactionid')); | |
641 | ||
642 | echo '<input type="hidden" name="id" value="'.$course->id.'" />'; | |
643 | echo '<noscript style="display:inline">'; | |
644 | echo '<div><input type="submit" value="'.get_string('ok').'" /></div>'; | |
645 | echo '</noscript>'; | |
646 | echo '</div></div>'; | |
647 | echo '</form>'; | |
648 | ||
649 | $module = array('name' => 'core_user', 'fullpath' => '/user/module.js'); | |
650 | $PAGE->requires->js_init_call('M.core_user.init_participation', null, false, $module); | |
651 | } | |
b90e2f19 | 652 | |
a2ed6e69 SH |
653 | // Show a search box if all participants don't fit on a single screen. |
654 | if ($totalcount > $perpage) { | |
655 | echo '<form action="index.php" class="searchform"><div><input type="hidden" name="id" value="'.$course->id.'" />'; | |
656 | echo '<label for="search">' . get_string('search', 'search') . ' </label>'; | |
657 | echo '<input type="text" id="search" name="search" value="'.s($search).'" /> <input type="submit" value="'.get_string('search').'" /></div></form>'."\n"; | |
658 | } | |
77c645df | 659 | |
a2ed6e69 | 660 | echo '</div>'; // Userlist. |
f9903ed0 | 661 | |
a2ed6e69 | 662 | echo $OUTPUT->footer(); |
77c645df | 663 | |
a2ed6e69 SH |
664 | if ($userlist) { |
665 | $userlist->close(); | |
666 | } | |
77c645df | 667 | |
a2ed6e69 SH |
668 | /** |
669 | * Returns SQL that can be used to limit a query to a period where the user last accessed a course.. | |
670 | * | |
671 | * @param string $accesssince | |
672 | * @return string | |
673 | */ | |
0749caef | 674 | function get_course_lastaccess_sql($accesssince='') { |
31b71336 | 675 | if (empty($accesssince)) { |
676 | return ''; | |
677 | } | |
a2ed6e69 | 678 | if ($accesssince == -1) { // Never. |
4f0c2d00 | 679 | return 'ul.timeaccess = 0'; |
31b71336 | 680 | } else { |
4f0c2d00 | 681 | return 'ul.timeaccess != 0 AND ul.timeaccess < '.$accesssince; |
0749caef | 682 | } |
683 | } | |
684 | ||
a2ed6e69 SH |
685 | /** |
686 | * Returns SQL that can be used to limit a query to a period where the user last accessed the system. | |
687 | * | |
688 | * @param string $accesssince | |
689 | * @return string | |
690 | */ | |
0749caef | 691 | function get_user_lastaccess_sql($accesssince='') { |
692 | if (empty($accesssince)) { | |
693 | return ''; | |
694 | } | |
a2ed6e69 | 695 | if ($accesssince == -1) { // Never. |
4f0c2d00 | 696 | return 'u.lastaccess = 0'; |
0749caef | 697 | } else { |
4f0c2d00 | 698 | return 'u.lastaccess != 0 AND u.lastaccess < '.$accesssince; |
31b71336 | 699 | } |
700 | } |