libdir.'/tablelib.php'); define('USER_SMALL_CLASS', 20); // Below this is considered small define('USER_LARGE_CLASS', 200); // Above this is considered large define('DEFAULT_PAGE_SIZE', 20); define('SHOW_ALL_PAGE_SIZE', 5000); define('MODE_BRIEF', 0); define('MODE_USERDETAILS', 1); define('MODE_ENROLDETAILS', 2); $page = optional_param('page', 0, PARAM_INT); // which page to show $perpage = optional_param('perpage', DEFAULT_PAGE_SIZE, PARAM_INT); // how many per page $mode = optional_param('mode', NULL); // use the MODE_ constants $accesssince = optional_param('accesssince',0,PARAM_INT); // filter by last access. -1 = never $search = optional_param('search','',PARAM_CLEAN); $roleid = optional_param('roleid', 0, PARAM_INT); // optional roleid, -1 means all site users on frontpage $contextid = optional_param('contextid', 0, PARAM_INT); // one of this or $courseid = optional_param('id', 0, PARAM_INT); // this are required if ($contextid) { if (! $context = get_context_instance_by_id($contextid)) { print_error('invalidcontext'); } if (! $course = $DB->get_record('course', array('id'=>$context->instanceid))) { print_error('invalidcourseid'); } } else { if (! $course = $DB->get_record('course', array('id'=>$courseid))) { print_error('invalidcourseid'); } if (! $context = get_context_instance(CONTEXT_COURSE, $course->id)) { print_error('invalidcontext'); } } // not needed anymore unset($contextid); unset($courseid); require_login($course); $systemcontext = get_context_instance(CONTEXT_SYSTEM); $frontpagectx = get_context_instance(CONTEXT_COURSE, SITEID); if ($context->id != $frontpagectx->id) { require_capability('moodle/course:viewparticipants', $context); } else { require_capability('moodle/site:viewparticipants', $systemcontext); // override the default on frontpage $roleid = optional_param('roleid', -1, PARAM_INT); } /// front page course is different $rolenames = array(); $avoidroles = array(); if ($roles = get_roles_used_in_context($context, true)) { // We should ONLY allow roles with moodle/course:view because otherwise we get little niggly issues // like MDL-8093 // We should further exclude "admin" users (those with "doanything" at site level) because // Otherwise they appear in every participant list $canviewroles = get_roles_with_capability('moodle/course:view', CAP_ALLOW, $context); $doanythingroles = get_roles_with_capability('moodle/site:doanything', CAP_ALLOW, $systemcontext); if ($context->id == $frontpagectx->id) { //we want admins listed on frontpage too foreach ($doanythingroles as $dar) { $canviewroles[$dar->id] = $dar; } $doanythingroles = array(); } foreach ($roles as $role) { if (!isset($canviewroles[$role->id])) { // Avoid this role (eg course creator) $avoidroles[] = $role->id; unset($roles[$role->id]); continue; } if (isset($doanythingroles[$role->id])) { // Avoid this role (ie admin) $avoidroles[] = $role->id; unset($roles[$role->id]); continue; } $rolenames[$role->id] = strip_tags(role_get_name($role, $context)); // Used in menus etc later on } } if ($context->id == $frontpagectx->id and $CFG->defaultfrontpageroleid) { // default frontpage role is assigned to all site users unset($rolenames[$CFG->defaultfrontpageroleid]); } // no roles to display yet? // frontpage course is an exception, on the front page course we should display all users if (empty($rolenames) && $context->id != $frontpagectx->id) { if (has_capability('moodle/role:assign', $context)) { redirect($CFG->wwwroot.'/'.$CFG->admin.'/roles/assign.php?contextid='.$context->id); } else { print_error('noparticipants'); } } add_to_log($course->id, 'user', 'view all', 'index.php?id='.$course->id, ''); $bulkoperations = has_capability('moodle/course:bulkmessaging', $context); $countries = get_list_of_countries(); $strnever = get_string('never'); $datestring->year = get_string('year'); $datestring->years = get_string('years'); $datestring->day = get_string('day'); $datestring->days = get_string('days'); $datestring->hour = get_string('hour'); $datestring->hours = get_string('hours'); $datestring->min = get_string('min'); $datestring->mins = get_string('mins'); $datestring->sec = get_string('sec'); $datestring->secs = get_string('secs'); if ($mode !== NULL) { $mode = (int)$mode; $SESSION->userindexmode = $mode; } else if (isset($SESSION->userindexmode)) { $mode = (int)$SESSION->userindexmode; } else { $mode = MODE_BRIEF; } /// Check to see if groups are being used in this course /// and if so, set $currentgroup to reflect the current group $groupmode = groups_get_course_groupmode($course); // Groups are being used $currentgroup = groups_get_course_group($course, true); if (!$currentgroup) { // To make some other functions work better later $currentgroup = NULL; } $isseparategroups = ($course->groupmode == SEPARATEGROUPS and $course->groupmodeforce and !has_capability('moodle/site:accessallgroups', $context)); if ($isseparategroups and (!$currentgroup) ) { $navlinks = array(); $navlinks[] = array('name' => get_string('participants'), 'link' => null, 'type' => 'misc'); $navigation = build_navigation($navlinks); print_header("$course->shortname: ".get_string('participants'), $course->fullname, $navigation, "", "", true, " ", navmenu($course)); print_heading(get_string("notingroup")); print_footer($course); exit; } // Should use this variable so that we don't break stuff every time a variable is added or changed. $baseurl = $CFG->wwwroot.'/user/index.php?contextid='.$context->id.'&roleid='.$roleid.'&id='.$course->id.'&perpage='.$perpage.'&accesssince='.$accesssince.'&search='.s($search); /// Print headers $navlinks = array(); $navlinks[] = array('name' => get_string('participants'), 'link' => null, 'type' => 'misc'); $navigation = build_navigation($navlinks); print_header("$course->shortname: ".get_string('participants'), $course->fullname, $navigation, "", "", true, " ", navmenu($course)); /// setting up tags if ($course->id == SITEID) { $filtertype = 'site'; } else if ($course->id && !$currentgroup) { $filtertype = 'course'; $filterselect = $course->id; } else { $filtertype = 'group'; $filterselect = $currentgroup; } $currenttab = 'participants'; $user = $USER; $userindexpage = true; require_once($CFG->dirroot .'/user/tabs.php'); /// Get the hidden field list if (has_capability('moodle/course:viewhiddenuserfields', $context)) { $hiddenfields = array(); // teachers and admins are allowed to see everything } else { $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields)); } if (isset($hiddenfields['lastaccess'])) { // do not allow access since filtering $accesssince = 0; } /// Print settings and things in a table across the top echo '
| '; $courselist = array(); foreach ($mycourses as $mycourse) { $courselist[$mycourse->id] = format_string($mycourse->shortname); } if (has_capability('moodle/site:viewparticipants', $systemcontext)) { unset($courselist[SITEID]); $courselist = array(SITEID => format_string($SITE->shortname)) + $courselist; } popup_form($CFG->wwwroot.'/user/index.php?roleid='.$roleid.'&sifirst=&silast=&id=', $courselist, 'courseform', $course->id, '', '', '', false, 'self', get_string('mycourses')); echo ' | '; } echo ''; groups_print_course_menu($course, $baseurl); echo ' | '; if (!isset($hiddenfields['lastaccess'])) { // get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far. // we need to make it diferently for normal courses and site course if ($context->id != $frontpagectx->id) { $minlastaccess = $DB->get_field_sql('SELECT min(timeaccess) FROM {user_lastaccess} WHERE courseid = ? AND timeaccess != 0', array($course->id)); $lastaccess0exists = $DB->record_exists('user_lastaccess', array('courseid'=>$course->id, 'timeaccess'=>0)); } else { $minlastaccess = $DB->get_field_sql('SELECT min(lastaccess) FROM {user} WHERE lastaccess != 0'); $lastaccess0exists = $DB->record_exists('user', array('lastaccess'=>0)); } $now = usergetmidnight(time()); $timeaccess = array(); // makes sense for this to go first. $timeoptions[0] = get_string('selectperiod'); // days for ($i = 1; $i < 7; $i++) { if (strtotime('-'.$i.' days',$now) >= $minlastaccess) { $timeoptions[strtotime('-'.$i.' days',$now)] = get_string('numdays','moodle',$i); } } // weeks for ($i = 1; $i < 10; $i++) { if (strtotime('-'.$i.' weeks',$now) >= $minlastaccess) { $timeoptions[strtotime('-'.$i.' weeks',$now)] = get_string('numweeks','moodle',$i); } } // months for ($i = 2; $i < 12; $i++) { if (strtotime('-'.$i.' months',$now) >= $minlastaccess) { $timeoptions[strtotime('-'.$i.' months',$now)] = get_string('nummonths','moodle',$i); } } // try a year if (strtotime('-1 year',$now) >= $minlastaccess) { $timeoptions[strtotime('-1 year',$now)] = get_string('lastyear'); } if (!empty($lastaccess0exists)) { $timeoptions[-1] = get_string('never'); } if (count($timeoptions) > 1) { echo ''; $baseurl = preg_replace('/&accesssince='.$accesssince.'/','',$baseurl); popup_form($baseurl.'&accesssince=',$timeoptions,'timeoptions',$accesssince, '', '', '', false, 'self', get_string('usersnoaccesssince')); echo ' | '; } } // Decide wheteher we will fetch extra enrolment/groups data. // // MODE_ENROLDETAILS is expensive, and only suitable where the listing is small // (at or below DEFAULT_PAGE_SIZE) and $USER can enrol/unenrol // (will take 1 extra DB query - 2 on Oracle) // if ($course->id != SITEID && $perpage <= DEFAULT_PAGE_SIZE && has_capability('moodle/role:assign',$context)) { $allowenroldetails=true; } else { $allowenroldetails=false; } if ($mode === MODE_ENROLDETAILS && !($allowenroldetails)) { // conditions haven't been met - reset $mode = MODE_BRIEF; } echo ''; $formatmenu = array( '0' => get_string('brief'), '1' => get_string('userdetails')); if ($allowenroldetails) { $formatmenu['2']= get_string('enroldetails'); } popup_form($baseurl.'&mode=', $formatmenu, 'formatmenu', $mode, '', '', '', false, 'self', get_string('userlist')); echo ' |
| '; print_group_picture($group, $course->id, true, false, false); echo ' | ';
echo ''.$group->name;
if (has_capability('moodle/course:managegroups', $context)) {
echo ' ';
echo '';
echo format_text($group->description);
echo ' |
';
}
print_heading($heading, 'center', 3);
} else {
if ($course->id != SITEID && has_capability('moodle/role:assign', $context)) {
$editlink = ' ';
$editlink .= '
';
} else {
$editlink = '';
}
if ($course->id == SITEID and $roleid < 0) {
$strallparticipants = get_string('allsiteusers', 'role');
} else {
$strallparticipants = get_string('allparticipants');
}
if ($matchcount < $totalcount) {
print_heading($strallparticipants.': '.$matchcount.'/'.$totalcount . $editlink, '', 3);
} else {
print_heading($strallparticipants.': '.$matchcount . $editlink, '', 3);
}
}
if ($bulkoperations) {
echo '
';
echo '';
}
if ($bulkoperations && $totalcount > ($perpage*3)) {
echo ''."\n";
}
$perpageurl = preg_replace('/&perpage=\d*/','', $baseurl);
if ($perpage == SHOW_ALL_PAGE_SIZE) {
echo '';
} else if ($matchcount > 0 && $perpage < $matchcount) {
echo '';
}
print_footer($course);
if ($userlist) {
$userlist->close();
}
function get_course_lastaccess_sql($accesssince='') {
if (empty($accesssince)) {
return '';
}
if ($accesssince == -1) { // never
return ' AND ul.timeaccess = 0';
} else {
return ' AND ul.timeaccess != 0 AND ul.timeaccess < '.$accesssince;
}
}
function get_user_lastaccess_sql($accesssince='') {
if (empty($accesssince)) {
return '';
}
if ($accesssince == -1) { // never
return ' AND u.lastaccess = 0';
} else {
return ' AND u.lastaccess != 0 AND u.lastaccess < '.$accesssince;
}
}
function get_participants_extra ($userids, $avoidroles, $course, $context) {
global $CFG, $DB;
if (count($userids) === 0 || count($avoidroles) === 0) {
return array();
}
$params = array();
$userids = implode(',', $userids);
// turn the path into a list of context ids
$contextids = substr($context->path, 1); // kill leading slash
$contextids = str_replace('/', ',', $contextids);;
if (count($avoidroles) > 0) {
$avoidroles = implode(',', $avoidroles);
$avoidrolescond = " AND ra.roleid NOT IN ($avoidroles) ";
} else {
$avoidrolescond = '';
}
if (!empty($CFG->enablegroupings)) {
$gpjoin = "LEFT OUTER JOIN {groupings_groups} gpg
ON gpg.groupid=g.id
LEFT OUTER JOIN {groupings} gp
ON (gp.courseid={$course->id} AND gp.id=gpg.groupingid)";
$gpselect = ',gp.id AS gpid, gp.name AS gpname ';
} else {
$gpjoin = '';
$gpselect = '';
}
// Note: this returns strange redundant rows, perhaps
// due to the multiple OUTER JOINs. If we can tweak the
// JOINs to avoid it ot
$sql = "SELECT DISTINCT ra.userid,
ctx.id AS ctxid, ctx.path AS ctxpath, ctx.depth AS ctxdepth,
ctx.contextlevel AS ctxlevel, ctx.instanceid AS ctxinstanceid,
cc.name AS ccname,
ra.roleid AS roleid,
ra.enrol AS enrolplugin,
g.id AS gid, g.name AS gname
$gpselect
FROM {role_assignments} ra
JOIN {context} ctx
ON (ra.contextid=ctx.id)
LEFT JOIN {course_categories} cc
ON (ctx.contextlevel=40 AND ctx.instanceid=cc.id)
/* only if groups active */
LEFT JOIN {groups_members} gm
ON (ra.userid=gm.userid)
LEFT JOIN {groups} g
ON (gm.groupid=g.id AND g.courseid={$course->id})
/* and if groupings is enabled... */
$gpjoin
WHERE ra.userid IN ( $userids )
AND ra.contextid in ( $contextids )
$avoidrolescond
ORDER BY ra.userid, ctx.depth DESC";
$rs = $DB->get_recordset_sql($sql, $params);
$extra = array();
// Data structure -
// $extra [ $userid ] [ 'group' ] [ $groupid => 'group name']
// [ 'gping' ] [ $gpingid => 'gping name']
// [ 'ra' ] [ [ "$ctxid:$roleid" => [ctxid => $ctxid
// ctxdepth => $ctxdepth,
// ctxpath => $ctxpath,
// ctxname => 'name' (categories only)
// ctxinstid =>
// roleid => $roleid
// enrol => $pluginname
//
// Might be interesting to add to RA timestart, timeend, timemodified,
// and modifierid (with an outer join to mdl_user!
//
foreach ($rs as $rec) {
$userid = $rec->userid;
// Prime an initial user rec...
if (!isset($extra[$userid])) {
$extra[$userid] = array( 'group' => array(),
'gping' => array(),
'ra' => array() );
}
if (!empty($rec->gid)) {
$extra[$userid]['group'][$rec->gid]= $rec->gname;
}
if (!empty($rec->gpid)) {
$extra[$userid]['gping'][$rec->gpid]= $rec->gpname;
}
$rakey = $rec->ctxid . ':' . $rec->roleid;
if (!isset($extra[$userid]['ra'][$rakey])) {
$extra[$userid]['ra'][$rakey] = array('ctxid' => $rec->ctxid,
'ctxlevel' => $rec->ctxlevel,
'ctxinstanceid' => $rec->ctxinstanceid,
'ccname' => $rec->ccname,
'roleid' => $rec->roleid,
'enrolplugin' => $rec->enrolplugin);
}
}
$rs->close();
return $extra;
}
?>