Merge branch 'MDL-59831_master' of git://github.com/markn86/moodle
[moodle.git] / user / index.php
CommitLineData
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
25require_once('../config.php');
0ff203b6 26require_once($CFG->dirroot.'/user/lib.php');
5fa2d502 27require_once($CFG->dirroot.'/course/lib.php');
a2ed6e69
SH
28require_once($CFG->libdir.'/tablelib.php');
29require_once($CFG->libdir.'/filelib.php');
a78ed71c 30require_once($CFG->dirroot.'/enrol/locallib.php');
a2ed6e69 31
a2ed6e69
SH
32define('DEFAULT_PAGE_SIZE', 20);
33define('SHOW_ALL_PAGE_SIZE', 5000);
9651e491
JP
34define('USER_FILTER_ENROLMENT', 1);
35define('USER_FILTER_GROUP', 2);
36define('USER_FILTER_LAST_ACCESS', 3);
37define('USER_FILTER_ROLE', 4);
38define('USER_FILTER_STATUS', 5);
a2ed6e69
SH
39
40$page = optional_param('page', 0, PARAM_INT); // Which page to show.
41$perpage = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT); // How many per page.
a2ed6e69
SH
42$contextid = optional_param('contextid', 0, PARAM_INT); // One of this or.
43$courseid = optional_param('id', 0, PARAM_INT); // This are required.
5fa2d502 44$newcourse = optional_param('newcourse', false, PARAM_BOOL);
5b7c500a 45$selectall = optional_param('selectall', false, PARAM_BOOL); // When rendering checkboxes against users mark them all checked.
a2ed6e69
SH
46
47$PAGE->set_url('/user/index.php', array(
48 'page' => $page,
49 'perpage' => $perpage,
a2ed6e69 50 'contextid' => $contextid,
5fa2d502
DW
51 'id' => $courseid,
52 'newcourse' => $newcourse));
a2ed6e69
SH
53
54if ($contextid) {
55 $context = context::instance_by_id($contextid, MUST_EXIST);
56 if ($context->contextlevel != CONTEXT_COURSE) {
57 print_error('invalidcontext');
58 }
59 $course = $DB->get_record('course', array('id' => $context->instanceid), '*', MUST_EXIST);
60} else {
61 $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
62 $context = context_course::instance($course->id, MUST_EXIST);
63}
64// Not needed anymore.
65unset($contextid);
66unset($courseid);
f9903ed0 67
a2ed6e69 68require_login($course);
f9903ed0 69
a2ed6e69
SH
70$systemcontext = context_system::instance();
71$isfrontpage = ($course->id == SITEID);
f9903ed0 72
a2ed6e69 73$frontpagectx = context_course::instance(SITEID);
4f0c2d00 74
a2ed6e69
SH
75if ($isfrontpage) {
76 $PAGE->set_pagelayout('admin');
93b47710 77 course_require_view_participants($systemcontext);
a2ed6e69
SH
78} else {
79 $PAGE->set_pagelayout('incourse');
93b47710 80 course_require_view_participants($context);
a2ed6e69 81}
224aa44a 82
0ff203b6
JL
83// Trigger events.
84user_list_view($course, $context);
a2ed6e69
SH
85
86$bulkoperations = has_capability('moodle/course:bulkmessaging', $context);
87
a2ed6e69
SH
88$PAGE->set_title("$course->shortname: ".get_string('participants'));
89$PAGE->set_heading($course->fullname);
90$PAGE->set_pagetype('course-view-' . $course->format);
91$PAGE->add_body_class('path-user'); // So we can style it independently.
92$PAGE->set_other_editing_capability('moodle/course:manageactivities');
2cb2ce61 93
b34fd2cc
DW
94// Expand the users node in the settings navigation when it exists because those pages
95// are related to this one.
96$node = $PAGE->settingsnav->find('users', navigation_node::TYPE_CONTAINER);
97if ($node) {
b0b6ff3c 98 $node->force_open();
b34fd2cc
DW
99}
100
a2ed6e69 101echo $OUTPUT->header();
4e1f6047 102echo $OUTPUT->heading(get_string('participants'));
caa8363f 103
9651e491
JP
104// Get the currently applied filters.
105$filtersapplied = optional_param_array('unified-filters', [], PARAM_TEXT);
32e5109d 106$filterwassubmitted = optional_param('unified-filter-submitted', 0, PARAM_BOOL);
a78ed71c 107
9651e491
JP
108// Default group ID.
109$groupid = false;
110$canaccessallgroups = has_capability('moodle/site:accessallgroups', $context);
111if ($course->groupmode != NOGROUPS) {
112 if ($canaccessallgroups) {
113 // If the user can see all groups, set default to 0.
114 $groupid = 0;
115 } else {
116 // Otherwise, get the user's default group.
117 $groupid = groups_get_course_group($course, true);
118 if ($course->groupmode == SEPARATEGROUPS && !$groupid) {
119 // The user is not in the group so show message and exit.
120 echo $OUTPUT->notification(get_string('notingroup'));
121 echo $OUTPUT->footer();
122 exit;
123 }
124 }
a2ed6e69 125}
9651e491
JP
126$hasgroupfilter = false;
127$lastaccess = 0;
128$searchkeywords = [];
129$roleid = 0;
130$enrolid = 0;
131$status = -1;
132foreach ($filtersapplied as $filter) {
133 $filtervalue = explode(':', $filter, 2);
134 $value = null;
135 if (count($filtervalue) == 2) {
136 $key = clean_param($filtervalue[0], PARAM_INT);
137 $value = clean_param($filtervalue[1], PARAM_INT);
138 } else {
139 // Search string.
140 $key = clean_param($filtervalue[0], PARAM_TEXT);
141 }
99cca847 142
9651e491
JP
143 switch ($key) {
144 case USER_FILTER_ENROLMENT:
145 $enrolid = $value;
146 break;
147 case USER_FILTER_GROUP:
148 $groupid = $value;
149 $hasgroupfilter = true;
150 break;
151 case USER_FILTER_LAST_ACCESS:
152 $lastaccess = $value;
153 break;
154 case USER_FILTER_ROLE:
155 $roleid = $value;
156 break;
157 case USER_FILTER_STATUS:
158 // We only accept active/suspended statuses.
159 if ($value == ENROL_USER_ACTIVE || $value == ENROL_USER_SUSPENDED) {
160 $status = $value;
161 }
162 break;
163 default:
164 // Search string.
165 if (!empty($key) && empty($value)) {
166 $searchkeywords[] = $key;
167 }
168 break;
169 }
a2ed6e69 170}
03d9401e 171
32e5109d
MN
172// If course supports groups we may need to set a default.
173if ($groupid !== false) {
174 // If we are in a course with visible groups and the user has not submitted anything and does not have
175 // access to all groups, then set a default group. This is the same behaviour in 3.3.
176 if (!$canaccessallgroups && !$filterwassubmitted && $course->groupmode == VISIBLEGROUPS) {
177 $filtersapplied[] = USER_FILTER_GROUP . ':' . $groupid;
178 } else if (!$canaccessallgroups && !$hasgroupfilter && $course->groupmode != VISIBLEGROUPS) {
179 // The user can't access all groups and has not set a group filter in a course where the groups are not visible
180 // then apply a default group filter.
181 $filtersapplied[] = USER_FILTER_GROUP . ':' . $groupid;
182 } else if (!$hasgroupfilter) { // No need for the group id to be set.
183 $groupid = false;
184 }
24c3db91 185}
a2ed6e69 186
9651e491
JP
187// Manage enrolments.
188$manager = new course_enrolment_manager($PAGE, $course);
189$enrolbuttons = $manager->get_manual_enrol_buttons();
190$enrolrenderer = $PAGE->get_renderer('core_enrol');
191$enrolbuttonsout = '';
192foreach ($enrolbuttons as $enrolbutton) {
193 $enrolbuttonsout .= $enrolrenderer->render($enrolbutton);
bc47b706 194}
9651e491 195echo html_writer::div($enrolbuttonsout, 'pull-right');
bc47b706 196
9651e491
JP
197// Render the unified filter.
198$renderer = $PAGE->get_renderer('core_user');
199echo $renderer->unified_filter($course, $context, $filtersapplied);
87a13824 200
9651e491 201echo '<div class="userlist">';
87a13824 202
9651e491
JP
203// Should use this variable so that we don't break stuff every time a variable is added or changed.
204$baseurl = new moodle_url('/user/index.php', array(
205 'contextid' => $context->id,
206 'id' => $course->id,
207 'perpage' => $perpage));
a2ed6e69 208
9651e491
JP
209$participanttable = new \core_user\participants_table($course->id, $groupid, $lastaccess, $roleid, $enrolid, $status,
210 $searchkeywords, $bulkoperations, $selectall);
bc47b706 211$participanttable->define_baseurl($baseurl);
77c645df 212
bc47b706
MN
213// Do this so we can get the total number of rows.
214ob_start();
215$participanttable->out($perpage, true);
216$participanttablehtml = ob_get_contents();
217ob_end_clean();
3e219038 218
a2ed6e69
SH
219if ($bulkoperations) {
220 echo '<form action="action_redir.php" method="post" id="participantsform">';
221 echo '<div>';
222 echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
223 echo '<input type="hidden" name="returnto" value="'.s($PAGE->url->out(false)).'" />';
224}
77c645df 225
bc47b706 226echo $participanttablehtml;
4c7593ff 227
8dd42b38
AH
228$perpageurl = clone($baseurl);
229$perpageurl->remove_params('perpage');
bc47b706 230if ($perpage == SHOW_ALL_PAGE_SIZE && $participanttable->totalrows > DEFAULT_PAGE_SIZE) {
8dd42b38
AH
231 $perpageurl->param('perpage', DEFAULT_PAGE_SIZE);
232 echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showperpage', '', DEFAULT_PAGE_SIZE)), array(), 'showall');
233
bc47b706 234} else if ($participanttable->get_page_size() < $participanttable->totalrows) {
8dd42b38 235 $perpageurl->param('perpage', SHOW_ALL_PAGE_SIZE);
bc47b706
MN
236 echo $OUTPUT->container(html_writer::link($perpageurl, get_string('showall', '', $participanttable->totalrows)),
237 array(), 'showall');
8dd42b38
AH
238}
239
a2ed6e69
SH
240if ($bulkoperations) {
241 echo '<br /><div class="buttons">';
5b7c500a 242
bc47b706 243 if ($participanttable->get_page_size() < $participanttable->totalrows) {
5b7c500a
AH
244 $perpageurl = clone($baseurl);
245 $perpageurl->remove_params('perpage');
246 $perpageurl->param('perpage', SHOW_ALL_PAGE_SIZE);
247 $perpageurl->param('selectall', true);
248 $showalllink = $perpageurl;
249 } else {
250 $showalllink = false;
251 }
252
b27c8d81 253 echo html_writer::start_tag('div', array('class' => 'btn-group'));
bc47b706 254 if ($participanttable->get_page_size() < $participanttable->totalrows) {
5b7c500a 255 // Select all users, refresh page showing all users and mark them all selected.
bc47b706 256 $label = get_string('selectalluserswithcount', 'moodle', $participanttable->totalrows);
b27c8d81
SB
257 echo html_writer::tag('input', "", array('type' => 'button', 'id' => 'checkall', 'class' => 'btn btn-secondary',
258 'value' => $label, 'data-showallink' => $showalllink));
5b7c500a 259 // Select all users, mark all users on page as selected.
b27c8d81
SB
260 echo html_writer::tag('input', "", array('type' => 'button', 'id' => 'checkallonpage', 'class' => 'btn btn-secondary',
261 'value' => get_string('selectallusersonpage')));
5b7c500a 262 } else {
b27c8d81
SB
263 echo html_writer::tag('input', "", array('type' => 'button', 'id' => 'checkallonpage', 'class' => 'btn btn-secondary',
264 'value' => get_string('selectall')));
5b7c500a
AH
265 }
266
b27c8d81
SB
267 echo html_writer::tag('input', "", array('type' => 'button', 'id' => 'checknone', 'class' => 'btn btn-secondary',
268 'value' => get_string('deselectall')));
269 echo html_writer::end_tag('div');
a2ed6e69
SH
270 $displaylist = array();
271 $displaylist['messageselect.php'] = get_string('messageselectadd');
272 if (!empty($CFG->enablenotes) && has_capability('moodle/notes:manage', $context) && $context->id != $frontpagectx->id) {
273 $displaylist['addnote.php'] = get_string('addnewnote', 'notes');
274 $displaylist['groupaddnote.php'] = get_string('groupaddnewnote', 'notes');
275 }
276
ca560952 277 if ($context->id != $frontpagectx->id) {
f4ddc4ec
DW
278 $instances = $manager->get_enrolment_instances();
279 $plugins = $manager->get_enrolment_plugins(false);
280 foreach ($instances as $key => $instance) {
281 if (!isset($plugins[$instance->enrol])) {
282 // Weird, some broken stuff in plugin.
283 continue;
284 }
285 $plugin = $plugins[$instance->enrol];
ca560952
DW
286 $bulkoperations = $plugin->get_bulk_operations($manager);
287
288 $pluginoptions = [];
289 foreach ($bulkoperations as $key => $bulkoperation) {
290 $params = ['plugin' => $plugin->get_name(), 'operation' => $key];
291 $url = new moodle_url('bulkchange.php', $params);
292 $pluginoptions[$url->out(false)] = $bulkoperation->get_title();
293 }
294 if (!empty($pluginoptions)) {
295 $name = get_string('pluginname', 'enrol_' . $plugin->get_name());
296 $displaylist[] = [$name => $pluginoptions];
297 }
689ccae5
DW
298 }
299 }
300
a2ed6e69
SH
301 echo $OUTPUT->help_icon('withselectedusers');
302 echo html_writer::tag('label', get_string("withselectedusers"), array('for' => 'formactionid'));
303 echo html_writer::select($displaylist, 'formaction', '', array('' => 'choosedots'), array('id' => 'formactionid'));
304
305 echo '<input type="hidden" name="id" value="'.$course->id.'" />';
306 echo '<noscript style="display:inline">';
307 echo '<div><input type="submit" value="'.get_string('ok').'" /></div>';
308 echo '</noscript>';
309 echo '</div></div>';
310 echo '</form>';
311
312 $module = array('name' => 'core_user', 'fullpath' => '/user/module.js');
313 $PAGE->requires->js_init_call('M.core_user.init_participation', null, false, $module);
314}
b90e2f19 315
a2ed6e69 316echo '</div>'; // Userlist.
f9903ed0 317
a78ed71c
DW
318$enrolrenderer = $PAGE->get_renderer('core_enrol');
319echo '<div class="pull-right">';
320foreach ($enrolbuttons as $enrolbutton) {
321 echo $enrolrenderer->render($enrolbutton);
322}
323echo '</div>';
324
5fa2d502
DW
325if ($newcourse == 1) {
326 $str = get_string('proceedtocourse', 'enrol');
327 // Floated left so it goes under the enrol users button on mobile.
328 // The margin is to make it line up with the enrol users button when they are both on the same line.
329 $classes = 'm-y-1 pull-xs-left';
330 $url = course_get_url($course);
331 echo $OUTPUT->single_button($url, $str, 'GET', array('class' => $classes));
332}
333
a2ed6e69 334echo $OUTPUT->footer();