e2fced2c48ac5a183379f5bd38c21e59bcfdd4ed
[moodle.git] / enrol / users.php
1 <?php
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/>.
17 /**
18  * Main course enrolment management UI, this is not compatible with frontpage course.
19  *
20  * @package    core
21  * @subpackage enrol
22  * @copyright  2010 Petr Skoda {@link http://skodak.org}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 require('../config.php');
27 require_once("$CFG->dirroot/enrol/users_forms.php");
28 require_once("$CFG->dirroot/group/lib.php");
30 $id      = required_param('id', PARAM_INT); // course id
31 $action  = optional_param('action', '', PARAM_ACTION);
32 $confirm = optional_param('confirm', 0, PARAM_BOOL);
34 $ifilter = optional_param('ifilter', 0, PARAM_INT); // only one instance
35 $page    = optional_param('page', 0, PARAM_INT);
36 $perpage = optional_param('perpage', 20, PARAM_INT);
37 $sort    = optional_param('sort', 'lastname', PARAM_ALPHA);
38 $dir     = optional_param('dir', 'ASC', PARAM_ALPHA);
41 $course = $DB->get_record('course', array('id'=>$id), '*', MUST_EXIST);
42 $context = get_context_instance(CONTEXT_COURSE, $course->id, MUST_EXIST);
44 require_login($course);
45 require_capability('moodle/course:enrolreview', $context);
47 if ($course->id == SITEID) {
48     redirect("$CFG->wwwroot/");
49 }
51 $managegroups = has_capability('moodle/course:managegroups', $context);
52 $instances = enrol_get_instances($course->id, true);
53 $plugins   = enrol_get_plugins(true);
54 $inames    = array();
55 foreach ($instances as $k=>$i) {
56     if (!isset($plugins[$i->enrol])) {
57         // weird, some broken stuff in plugin
58         unset($instances[$k]);
59         continue;
60     }
61     $inames[$k] = $plugins[$i->enrol]->get_instance_name($i);
62 }
64 // validate paging params
65 if ($ifilter != 0 and !isset($instances[$ifilter])) {
66     $ifilter = 0;
67 }
68 if ($perpage < 3) {
69     $perpage = 3;
70 }
71 if ($page < 0) {
72     $page = 0;
73 }
74 if (!in_array($dir, array('ASC', 'DESC'))) {
75     $dir = 'ASC';
76 }
77 if (!in_array($sort, array('firstname', 'lastname', 'email', 'lastseen'))) {
78     $dir = 'lastname';
79 }
81 $PAGE->set_url('/enrol/users.php', array('id'=>$course->id, 'page'=>$page, 'sort'=>$sort, 'dir'=>$dir, 'perpage'=>$perpage, 'ifilter'=>$ifilter));
82 $PAGE->set_pagelayout('admin');
84 //lalala- nav hack
85 navigation_node::override_active_url(new moodle_url('/enrol/users.php', array('id'=>$course->id)));
88 $allroles   = get_all_roles();
89 $allroles   = role_fix_names($allroles, $context);
90 $assignable = get_assignable_roles($context, ROLENAME_ALIAS, false); // verifies unassign access control too
91 $allgroups  = groups_get_all_groups($course->id);
92 foreach ($allgroups as $gid=>$group) {
93     $allgroups[$gid]->name = format_string($group->name);
94 }
96 if ($action) {
97     switch ($action) {
98         case 'unenrol':
99             $ue = required_param('ue', PARAM_INT);
100             if (!$ue = $DB->get_record('user_enrolments', array('id'=>$ue))) {
101                 break;
102             }
103             $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST);
104             if (!isset($instances[$ue->enrolid])) {
105                 break;
106             }
107             $instance = $instances[$ue->enrolid];
108             $plugin = $plugins[$instance->enrol];
109             if (!$plugin->allow_unenrol($instance) or !has_capability("enrol/$instance->enrol:unenrol", $context)) {
110                 break;
111             }
113             if ($confirm and confirm_sesskey()) {
114                 $plugin->unenrol_user($instance, $ue->userid);
115                 redirect($PAGE->url);
117             } else {
118                 $yesurl = new moodle_url($PAGE->url, array('action'=>'unenrol', 'ue'=>$ue->id, 'confirm'=>1, 'sesskey'=>sesskey()));
119                 $message = get_string('unenrolconfirm', 'enrol', array('user'=>fullname($user, true), 'course'=>format_string($course->fullname)));
120                 $PAGE->set_title(get_string('unenrol', 'enrol'));
121                 echo $OUTPUT->header();
122                 echo $OUTPUT->heading(get_string('unenrol', 'enrol'));
123                 echo $OUTPUT->confirm($message, $yesurl, $PAGE->url);
124                 echo $OUTPUT->footer();
125                 die;
126             }
127             break;
129         case 'unassign':
130             $role = required_param('role', PARAM_INT);
131             $user = required_param('user', PARAM_INT);
132             if (!isset($assignable[$role])) {
133                 break;
134             }
135             $role = $allroles[$role];
136             $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST);
138             if ($confirm and confirm_sesskey()) {
139                 role_unassign($role->id, $user->id, $context->id, '', NULL);
140                 redirect($PAGE->url);
142             } else {
143                 $yesurl = new moodle_url($PAGE->url, array('action'=>'unassign', 'role'=>$role->id, 'user'=>$user->id, 'confirm'=>1, 'sesskey'=>sesskey()));
144                 $message = get_string('unassignconfirm', 'role', array('user'=>fullname($user, true), 'role'=>$role->localname));
145                 $PAGE->set_title(get_string('unassignarole', 'role', $role->localname));
146                 echo $OUTPUT->header();
147                 echo $OUTPUT->heading(get_string('unassignarole', 'role', $role->localname));
148                 echo $OUTPUT->confirm($message, $yesurl, $PAGE->url);
149                 echo $OUTPUT->footer();
150                 die;
151             }
152             break;
154         case 'assign':
155             $user = required_param('user', PARAM_INT);
156             $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST);
158             if (!is_enrolled($context, $user)) {
159                 break; // no roles without enrolments here in this script
160             }
162             $mform = new enrol_users_assign_form(NULL, array('user'=>$user, 'course'=>$course, 'assignable'=>$assignable));
164             if ($mform->is_cancelled()) {
165                 redirect($PAGE->url);
167             } else if ($data = $mform->get_data()) {
168                 if ($data->roleid) {
169                     role_assign($data->roleid, $user->id, $context->id, '', NULL);
170                 }
171                 redirect($PAGE->url);
172             }
174             $PAGE->set_title(get_string('assignroles', 'role'));
175             echo $OUTPUT->header();
176             echo $OUTPUT->heading(get_string('assignroles', 'role'));
177             $mform->display();
178             echo $OUTPUT->footer();
179             die;
181         case 'removemember':
182             $group = required_param('group', PARAM_INT);
183             $user  = required_param('user', PARAM_INT);
184             if (!$managegroups) {
185                 break;
186             }
187             if (!isset($allgroups[$group])) {
188                 break;
189             }
190             $group = $allgroups[$group];
191             $user  = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST);
193             if ($confirm and confirm_sesskey()) {
194                 groups_remove_member($group, $user);
195                 redirect($PAGE->url);
197             } else {
198                 $yesurl = new moodle_url($PAGE->url, array('action'=>'removemember', 'group'=>$group->id, 'user'=>$user->id, 'confirm'=>1, 'sesskey'=>sesskey()));
199                 $message = get_string('removefromgroupconfirm', 'group', array('user'=>fullname($user, true), 'group'=>$group->name));
200                 $PAGE->set_title(get_string('removefromgroup', 'group', $group->name));
201                 echo $OUTPUT->header();
202                 echo $OUTPUT->heading(get_string('removefromgroup', 'group', $group->name));
203                 echo $OUTPUT->confirm($message, $yesurl, $PAGE->url);
204                 echo $OUTPUT->footer();
205                 die;
206             }
207             break;
209         case 'addmember':
210             $user = required_param('user', PARAM_INT);
211             $user = $DB->get_record('user', array('id'=>$user), '*', MUST_EXIST);
213             if (!$managegroups) {
214                 break;
215             }
216             if (!is_enrolled($context, $user)) {
217                 break; // no roles without enrolments here in this script
218             }
220             $mform = new enrol_users_addmember_form(NULL, array('user'=>$user, 'course'=>$course, 'allgroups'=>$allgroups));
222             if ($mform->is_cancelled()) {
223                 redirect($PAGE->url);
225             } else if ($data = $mform->get_data()) {
226                 if ($data->groupid) {
227                     groups_add_member($data->groupid, $user->id);
228                 }
229                 redirect($PAGE->url);
230             }
232             $PAGE->set_title(get_string('addgroup', 'group'));
233             echo $OUTPUT->header();
234             echo $OUTPUT->heading(get_string('addgroup', 'group'));
235             $mform->display();
236             echo $OUTPUT->footer();
237             die;
239         case 'edit':
240             $ue = required_param('ue', PARAM_INT);
241             if (!$ue = $DB->get_record('user_enrolments', array('id'=>$ue))) {
242                 break;
243             }
244             $user = $DB->get_record('user', array('id'=>$ue->userid), '*', MUST_EXIST);
245             if (!isset($instances[$ue->enrolid])) {
246                 break;
247             }
248             $instance = $instances[$ue->enrolid];
249             $plugin = $plugins[$instance->enrol];
250             if (!$plugin->allow_unenrol($instance) or !has_capability("enrol/$instance->enrol:unenrol", $context)) {
251                 break;
252             }
254             $mform = new enrol_users_edit_form(NULL, array('user'=>$user, 'course'=>$course, 'ue'=>$ue));
256             if ($mform->is_cancelled()) {
257                 redirect($PAGE->url);
259             } else if ($data = $mform->get_data()) {
260                 if (!isset($data->status)) {
261                     $status = $ue->status;
262                 }
263                 $plugin->update_user_enrol($instance, $ue->userid, $data->status, $data->timestart, $data->timeend);
264                 redirect($PAGE->url);
265             }
267             $PAGE->set_title(fullname($user));
268             echo $OUTPUT->header();
269             echo $OUTPUT->heading(fullname($user));
270             $mform->display();
271             echo $OUTPUT->footer();
272             die;
273     }
277 echo $OUTPUT->header();
278 echo $OUTPUT->heading(get_string('enrolledusers', 'enrol'));
279 $PAGE->set_title(get_string('enrolledusers', 'enrol'));
281 notify('NOTICE TO TESTERS: This interface will shortly be replaced with a new one.');   // TODO FIXME REMOVE THIS
283 if ($ifilter) {
284     $instancessql = " = :ifilter";
285     $params = array('ifilter'=>$ifilter);
286 } else {
287     if ($instances) {
288         list($instancessql, $params) = $DB->get_in_or_equal(array_keys($instances), SQL_PARAMS_NAMED);
289     } else {
290         // no enabled instances, oops, we should probably say something
291         $instancessql = "= :never";
292         $params = array('never'=>-1);
293     }
296 $sqltotal = "SELECT COUNT(DISTINCT u.id)
297                FROM {user} u
298                JOIN {user_enrolments} ue ON (ue.userid = u.id  AND ue.enrolid $instancessql)
299                JOIN {enrol} e ON (e.id = ue.enrolid)";
300 $totalusers = $DB->count_records_sql($sqltotal, $params);
302 $ufields = user_picture::fields('u');
303 $sql = "SELECT DISTINCT $ufields, ul.timeaccess AS lastseen
304           FROM {user} u
305           JOIN {user_enrolments} ue ON (ue.userid = u.id  AND ue.enrolid $instancessql)
306           JOIN {enrol} e ON (e.id = ue.enrolid)
307      LEFT JOIN {user_lastaccess} ul ON (ul.courseid = e.courseid AND ul.userid = u.id)";
308 if ($sort === 'firstname') {
309     $sql .= " ORDER BY u.firstname $dir, u.lastname $dir";
310 } else if ($sort === 'lastname') {
311     $sql .= " ORDER BY u.lastname $dir, u.firstname $dir";
312 } else if ($sort === 'email') {
313     $sql .= " ORDER BY u.email $dir, u.lastname $dir, u.firstname $dir";
314 } else if ($sort === 'lastseen') {
315     $sql .= " ORDER BY ul.timeaccess $dir, u.lastname $dir, u.firstname $dir";
318 $pagingbar = new paging_bar($totalusers, $page, $perpage, $PAGE->url, 'page');
320 $users = $DB->get_records_sql($sql, $params, $page*$perpage, $perpage);
322 $strfirstname = get_string('firstname');
323 $strlastname  = get_string('lastname');
324 $stremail     = get_string('email');
325 $strlastseen  = get_string('lastaccess');
327 if ($dir === 'ASC') {
328     $diricon = html_writer::empty_tag('img', array('alt'=>'', 'src'=>$OUTPUT->pix_url('t/down')));
329     $newdir = 'DESC';
330 } else {
331     $diricon  = html_writer::empty_tag('img', array('alt'=>'', 'src'=>$OUTPUT->pix_url('t/up')));
332     $newdir = 'ASC';
335 $table = new html_table();
336 $table->head = array();
337 if ($sort === 'firstname') {
338     $h = html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $strfirstname);
339     $h .= " $diricon / ";
340     $h .= html_writer::link(new moodle_url($PAGE->url, array('sort'=>'lastname')), $strlastname);
341 } else if ($sort === 'lastname') {
342     $newdir = ($dir === 'ASC') ? 'DESC' : 'ASC';
343     $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'firstname')), $strfirstname);
344     $h .= " / ";
345     $h .= html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $strlastname);
346     $h .= " $diricon";
347 } else {
348     $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'firstname')), $strfirstname);
349     $h .= " / ";
350     $h .= html_writer::link(new moodle_url($PAGE->url, array('sort'=>'lastname')), $strlastname);
352 $table->head[] = $h;
353 if ($sort === 'email') {
354     $h = html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $stremail);
355     $h .= " $diricon";
356 } else {
357     $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'email')), $stremail);
359 $table->head[] = $h;
360 if ($sort === 'lastseen') {
361     $h = html_writer::link(new moodle_url($PAGE->url, array('dir'=>$newdir)), $strlastseen);
362     $h .= " $diricon";
363 } else {
364     $h = html_writer::link(new moodle_url($PAGE->url, array('sort'=>'lastseen')), $strlastseen);
366 $table->head[] = $h;
367 $table->head[] = get_string('roles', 'role');
368 $table->head[] = get_string('groups', 'group');
369 $table->head[] = get_string('enrolmentinstances', 'enrol');
371 $table->align = array('left', 'left', 'left', 'left', 'left', 'left');
372 $table->width = "95%";
373 foreach ($users as $user) {
374     $picture = $OUTPUT->user_picture($user, array('courseid'=>$course->id));
376     if ($user->lastseen) {
377         $strlastaccess = userdate($user->lastseen);
378     } else {
379         $strlastaccess = get_string('never');
380     }
381     $fullname = fullname($user, true);
383     // get list of roles
384     $roles = array();
385     $ras = get_user_roles($context, $user->id, true, 'c.contextlevel DESC, r.sortorder ASC');
386     foreach ($ras as $ra) {
387         if ($ra->contextid != $context->id) {
388             if (!isset($roles[$ra->roleid])) {
389                 $roles[$ra->roleid] = null;
390             }
391             // higher ras, course always takes precedence
392             continue;
393         }
394         if (isset($roles[$ra->roleid]) and $roles[$ra->roleid] === false) {
395             continue;
396         }
397         $roles[$ra->roleid] = ($ra->itemid == 0 and $ra->component === '');
398     }
399     foreach ($roles as $rid=>$unassignable) {
400         if ($unassignable and isset($assignable[$rid])) {
401             $icon = html_writer::empty_tag('img', array('alt'=>get_string('unassignarole', 'role', $allroles[$rid]->localname), 'src'=>$OUTPUT->pix_url('t/delete')));
402             $url = new moodle_url($PAGE->url, array('action'=>'unassign', 'role'=>$rid, 'user'=>$user->id));
403             $roles[$rid] = $allroles[$rid]->localname . html_writer::link($url, $icon);
404         } else {
405             $roles[$rid] = $allroles[$rid]->localname;
406         }
407     }
408     $addrole = '';
409     if ($assignable) {
410         foreach ($assignable as $rid=>$unused) {
411             if (!isset($roles[$rid])) {
412                 //candidate for role assignment
413                 $icon = html_writer::empty_tag('img', array('alt'=>get_string('assignroles', 'role'), 'src'=>$OUTPUT->pix_url('t/add')));
414                 $url = new moodle_url($PAGE->url, array('action'=>'assign', 'user'=>$user->id));
415                 $addrole .= html_writer::link($url, $icon);
416                 break;
417             }
418         }
419     }
420     $roles = implode(', ', $roles);
421     if ($addrole) {
422         $roles = $roles . '<div>'.$addrole.'</div>';
423     }
425     $groups = array();
426     $usergroups = groups_get_all_groups($course->id, $user->id, 0, 'g.id');
427     foreach($usergroups as $gid=>$unused) {
428         $group = $allgroups[$gid];
429         if ($managegroups) {
430             $icon = html_writer::empty_tag('img', array('alt'=>get_string('removefromgroup', 'group', $group->name), 'src'=>$OUTPUT->pix_url('t/delete')));
431             $url = new moodle_url($PAGE->url, array('action'=>'removemember', 'group'=>$gid, 'user'=>$user->id));
432             $groups[] = $group->name . html_writer::link($url, $icon);
433         } else {
434             $groups[] = $group->name;
435         }
436     }
437     $groups = implode(', ', $groups);
438     if ($managegroups and (count($usergroups) < count($allgroups))) {
439         $icon = html_writer::empty_tag('img', array('alt'=>get_string('addgroup', 'group'), 'src'=>$OUTPUT->pix_url('t/add')));
440         $url = new moodle_url($PAGE->url, array('action'=>'addmember', 'user'=>$user->id));
441         $groups .= '<div>'.html_writer::link($url, $icon).'</div>';
442     }
445     // get list of enrol instances
446     $now = time();
447     $edits = array();
448     $params['userid'] = $user->id;
449     $ues = $DB->get_records_select('user_enrolments', "enrolid $instancessql AND userid = :userid", $params);
450     foreach ($ues as $ue) {
451         $instance = $instances[$ue->enrolid];
452         $plugin   = $plugins[$instance->enrol];
454         $edit = $inames[$instance->id];
456         $dimmed = false;
457         if ($ue->timestart and $ue->timeend) {
458             $edit .= '&nbsp;('.get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend))).')';
459             $dimmed = ($now < $ue->timestart and $now > $ue->timeend);
460         } else if ($ue->timestart) {
461             $edit .= '&nbsp;('.get_string('periodstart', 'enrol', userdate($ue->timestart)).')';
462             $dimmed = ($now < $ue->timestart);
463         } else if ($ue->timeend) {
464             $edit .= '&nbsp;('.get_string('periodend', 'enrol', userdate($ue->timeend)).')';
465             $dimmed = ($now > $ue->timeend);
466         }
468         if ($dimmed or $ue->status != ENROL_USER_ACTIVE) {
469             $edit = html_writer::tag('span', $edit, array('class'=>'dimmed_text'));
470         }
472         if ($plugin->allow_unenrol($instance) and has_capability("enrol/$instance->enrol:unenrol", $context)) {
473             $icon = html_writer::empty_tag('img', array('alt'=>get_string('unenrol', 'enrol'), 'src'=>$OUTPUT->pix_url('t/delete')));
474             $url = new moodle_url($PAGE->url, array('action'=>'unenrol', 'ue'=>$ue->id));
475             $edit .= html_writer::link($url, $icon);
476         }
478         if ($plugin->allow_manage($instance) and has_capability("enrol/$instance->enrol:manage", $context)) {
479             $icon = html_writer::empty_tag('img', array('alt'=>get_string('edit'), 'src'=>$OUTPUT->pix_url('t/edit')));
480             $url = new moodle_url($PAGE->url, array('action'=>'edit', 'ue'=>$ue->id));
481             $edit .= html_writer::link($url, $icon);
482         }
484         $edits[] = $edit;
485     }
486     $edits = implode('<br />', $edits);
488     $table->data[] = array("$picture <a href=\"$CFG->wwwroot/user/view.php?id=$user->id&amp;course=$course->id\">$fullname</a>", $user->email, $strlastaccess, $roles, $groups, $edits);
491 $ifilters = new single_select($PAGE->url, 'ifilter', array(0=>get_string('all')) + $inames, $ifilter, array());
492 $ifilters->set_label(get_string('enrolmentinstances', 'enrol'));
494 echo $OUTPUT->render($ifilters);
495 echo $OUTPUT->render($pagingbar);
496 echo html_writer::table($table);
497 echo $OUTPUT->render($pagingbar);
499 // print enrol link or selection
500 $links = array();
501 foreach($instances as $instance) {
502     $plugin = $plugins[$instance->enrol];
503     if ($link = $plugin->get_manual_enrol_link($instance)) {
504         $links[$instance->id] = $link;
505     }
507 if (count($links) == 1) {
508     $link = reset($links);
509     echo $OUTPUT->single_button($link, get_string('enrolusers', 'enrol_manual'), 'get');
511 } else if (count($links) > 1) {
512     $options = array();
513     foreach ($links as $i=>$link) {
514         $options[$link->out(false)] = $inames[$i];
515     }
516     echo $OUTPUT->url_select($options, '', array(''=>get_string('enrolusers', 'enrol_manual').'...'));
519 echo $OUTPUT->footer();