/** * Return all courses this rule applies to. * * @return array A list of courses. */ public function get_courses() { global $CFG, $DB; if (isset($this->courses)) { return $this->courses; } require_once $CFG->libdir . '/coursecatlib.php'; $coursecat = \coursecat::get($this->id); $courselist = $coursecat->get_courses(array('recursive' => true, 'idonly' => true)); // Generate the SQL. list($sql, $params) = $DB->get_in_or_equal($courselist); $ctxlevel = \CONTEXT_COURSE; $preload = \context_helper::get_preload_record_columns_sql('ctx'); $sql = <<<SQL SELECT c.*, {$preload} FROM {course} c INNER JOIN {context} ctx ON ctx.instanceid = c.id AND ctx.contextlevel = {$ctxlevel} WHERE c.id {$sql} SQL; // Get the courses and preload contexts. $this->courses = $DB->get_records_sql($sql, $params); foreach ($this->courses as $course) { \context_helper::preload_from_record($course); } return $this->courses; }
/** * Returns shortname of activities in course * * @param int $courseid id of course for which activity shortname is needed * @return string|bool list of child shortname */ function block_course_overview_get_child_shortnames($courseid) { global $DB; $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT c.id, c.shortname, {$ctxselect}\n FROM {enrol} e\n JOIN {course} c ON (c.id = e.customint1)\n JOIN {context} ctx ON (ctx.instanceid = e.customint1)\n WHERE e.courseid = :courseid AND e.enrol = :method AND ctx.contextlevel = :contextlevel ORDER BY e.sortorder"; $params = array('method' => 'meta', 'courseid' => $courseid, 'contextlevel' => CONTEXT_COURSE); if ($results = $DB->get_records_sql($sql, $params)) { $shortnames = array(); // Preload the context we will need it to format the category name shortly. foreach ($results as $res) { context_helper::preload_from_record($res); $context = context_course::instance($res->id); $shortnames[] = format_string($res->shortname, true, $context); } $total = count($shortnames); $suffix = ''; if ($total > 10) { $shortnames = array_slice($shortnames, 0, 10); $diff = $total - count($shortnames); if ($diff > 1) { $suffix = get_string('shortnamesufixprural', 'block_course_overview', $diff); } else { $suffix = get_string('shortnamesufixsingular', 'block_course_overview', $diff); } } $shortnames = get_string('shortnameprefix', 'block_course_overview', implode('; ', $shortnames)); $shortnames .= $suffix; } return isset($shortnames) ? $shortnames : false; }
public function definition() { global $CFG, $DB; $mform = $this->_form; $course = $this->_customdata['course']; $instance = $this->_customdata['instance']; $this->course = $course; $existing = array(); if ($instance) { $existing = $DB->get_records('enrol_metaplus', array('enrolid' => $instance->id), '', 'courseid, id'); } $courses = array(); $select = context_helper::get_preload_record_columns_sql('ctx'); $sql = <<<SQL SELECT c.id, c.fullname, c.shortname, c.visible, {$select} FROM {course} c LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel) SQL; $rs = $DB->get_recordset_sql($sql, array('contextlevel' => CONTEXT_COURSE)); foreach ($rs as $c) { if ($c->id == SITEID || $c->id == $course->id) { continue; } context_helper::preload_from_record($c); $coursecontext = context_course::instance($c->id); if (!$c->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { continue; } if (!has_capability('enrol/meta:selectaslinked', $coursecontext)) { continue; } $courses[$c->id] = $coursecontext->get_context_name(false); } $rs->close(); $mform->addElement('header', 'general', get_string('pluginname', 'enrol_meta')); $mform->addElement('select', 'link', get_string('linkedcourse', 'enrol_metaplus'), $courses, array('multiple' => 'multiple', 'class' => 'chosen')); $mform->addRule('link', get_string('required'), 'required', null, 'server'); // Add role sync list. $coursecontext = \context_course::instance($course->id); $roles = get_assignable_roles($coursecontext); $mform->addElement('select', 'roleexclusions', get_string('roleexclusions', 'enrol_metaplus'), $roles, array('multiple' => 'multiple')); $mform->addElement('hidden', 'id', null); $mform->setType('id', PARAM_INT); $mform->addElement('hidden', 'enrolid'); $mform->setType('enrolid', PARAM_INT); $data = array('id' => $course->id); if ($instance) { $data['link'] = implode(',', array_keys($existing)); $data['enrolid'] = $instance->id; $data['roleexclusions'] = $instance->customtext1; $this->add_action_buttons(); } else { $this->add_add_buttons(); } $this->set_data($data); }
/** * Return the courses where both competency and user are. * * A user is considered being in a course when they are enrolled, the enrolment is valid, * the enrolment instance is enabled, and the enrolment plugin is enabled.. * * @param int $competencyid The competency ID. * @param int $userid The user ID. * @return array Indexed by course ID. */ public static function get_courses_with_competency_and_user($competencyid, $userid) { global $CFG, $DB; if (!($plugins = explode(',', $CFG->enrol_plugins_enabled))) { return array(); } $ctxfields = \context_helper::get_preload_record_columns_sql('ctx'); list($plugins, $params) = $DB->get_in_or_equal($plugins, SQL_PARAMS_NAMED, 'ee'); $params['competencyid'] = $competencyid; $params['userid'] = $userid; $params['enabled'] = ENROL_INSTANCE_ENABLED; $params['active'] = ENROL_USER_ACTIVE; $params['contextlevel'] = CONTEXT_COURSE; // Heavily based on enrol_get_shared_courses(). $sql = "SELECT c.*, {$ctxfields}\n FROM {course} c\n JOIN {" . static::TABLE . "} cc\n ON cc.courseid = c.id\n AND cc.competencyid = :competencyid\n JOIN (\n SELECT DISTINCT c.id\n FROM {enrol} e\n JOIN {user_enrolments} ue\n ON ue.enrolid = e.id\n AND ue.status = :active\n AND ue.userid = :userid\n JOIN {course} c\n ON c.id = e.courseid\n WHERE e.status = :enabled\n AND e.enrol {$plugins}\n ) ec ON ec.id = c.id\n LEFT JOIN {context} ctx\n ON ctx.instanceid = c.id\n AND ctx.contextlevel = :contextlevel\n ORDER BY c.id"; $courses = $DB->get_records_sql($sql, $params); array_map('context_helper::preload_from_record', $courses); return $courses; }
function definition() { global $CFG, $DB; $mform = $this->_form; $course = $this->_customdata; $this->course = $course; $existing = $DB->get_records('enrol', array('enrol' => 'meta', 'courseid' => $course->id), '', 'customint1, id'); // TODO: this has to be done via ajax or else it will fail very badly on large sites! $courses = array('' => get_string('choosedots')); $select = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $join = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; $plugin = enrol_get_plugin('meta'); $sortorder = 'c.' . $plugin->get_config('coursesort', 'sortorder') . ' ASC'; $sql = "SELECT c.id, c.fullname, c.shortname, c.visible {$select} FROM {course} c {$join} ORDER BY " . $sortorder; $rs = $DB->get_recordset_sql($sql, array('contextlevel' => CONTEXT_COURSE)); foreach ($rs as $c) { if ($c->id == SITEID or $c->id == $course->id or isset($existing[$c->id])) { continue; } context_helper::preload_from_record($c); $coursecontext = context_course::instance($c->id); if (!$c->visible and !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { continue; } if (!has_capability('enrol/meta:selectaslinked', $coursecontext)) { continue; } $courses[$c->id] = $coursecontext->get_context_name(false); } $rs->close(); $mform->addElement('header', 'general', get_string('pluginname', 'enrol_meta')); $mform->addElement('select', 'link', get_string('linkedcourse', 'enrol_meta'), $courses); $mform->addRule('link', get_string('required'), 'required', null, 'client'); $mform->addElement('hidden', 'id', null); $mform->setType('id', PARAM_INT); $this->add_action_buttons(true, get_string('addinstance', 'enrol')); $this->set_data(array('id' => $course->id)); }
/** * Get courses tagged with a tag * * @deprecated since 3.0 * @package core_tag * @category tag * @param int $tagid * @return array of course objects */ function coursetag_get_tagged_courses($tagid) { debugging('Function coursetag_get_tagged_courses() is deprecated. Userid is no longer used for tagging courses.', DEBUG_DEVELOPER); global $DB; $courses = array(); $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT c.*, {$ctxselect}\n FROM {course} c\n JOIN {tag_instance} t ON t.itemid = c.id\n JOIN {context} ctx ON ctx.instanceid = c.id\n WHERE t.tagid = :tagid AND\n t.itemtype = 'course' AND\n ctx.contextlevel = :contextlevel\n ORDER BY c.sortorder ASC"; $params = array('tagid' => $tagid, 'contextlevel' => CONTEXT_COURSE); $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $course) { context_helper::preload_from_record($course); if ($course->visible == 1 || has_capability('moodle/course:viewhiddencourses', context_course::instance($course->id))) { $courses[$course->id] = $course; } } return $courses; }
/** * Returns the default courses to display on the calendar when there isn't a specific * course to display. * * @return array $courses Array of courses to display */ function calendar_get_default_courses() { global $CFG, $DB; if (!isloggedin()) { return array(); } $courses = array(); if (!empty($CFG->calendar_adminseesall) && has_capability('moodle/calendar:manageentries', context_system::instance())) { $select = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $join = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; $sql = "SELECT c.* {$select}\n FROM {course} c\n {$join}\n WHERE EXISTS (SELECT 1 FROM {event} e WHERE e.courseid = c.id)\n "; $courses = $DB->get_records_sql($sql, array('contextlevel' => CONTEXT_COURSE), 0, 20); foreach ($courses as $course) { context_helper::preload_from_record($course); } return $courses; } $courses = enrol_get_my_courses(); return $courses; }
/** * Preloads context information together with instances. * Use context_instance_preload() to strip the context info from the record and cache the context instance. * * @deprecated * @param string $joinon for example 'u.id' * @param string $contextlevel context level of instance in $joinon * @param string $tablealias context table alias * @return array with two values - select and join part */ function context_instance_preload_sql($joinon, $contextlevel, $tablealias) { $select = ", " . context_helper::get_preload_record_columns_sql($tablealias); $join = "LEFT JOIN {context} {$tablealias} ON ({$tablealias}.instanceid = {$joinon} AND {$tablealias}.contextlevel = {$contextlevel})"; return array($select, $join); }
/** * Set the value of this element. If values can be added or are unknown, we will * make sure they exist in the options array. * @param string|array $value The value to set. * @return boolean */ public function setValue($value) { global $DB; $values = (array) $value; $coursestofetch = array(); foreach ($values as $onevalue) { if (!$this->optionExists($onevalue) && $onevalue !== '_qf__force_multiselect_submission') { array_push($coursestofetch, $onevalue); } } if (empty($coursestofetch)) { return $this->setSelected(array()); } // There is no API function to load a list of course from a list of ids. $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); $fields = array('c.id', 'c.category', 'c.sortorder', 'c.shortname', 'c.fullname', 'c.idnumber', 'c.startdate', 'c.visible', 'c.cacherev'); list($whereclause, $params) = $DB->get_in_or_equal($coursestofetch, SQL_PARAMS_NAMED, 'id'); $sql = "SELECT " . join(',', $fields) . ", {$ctxselect}\n FROM {course} c\n JOIN {context} ctx ON c.id = ctx.instanceid AND ctx.contextlevel = :contextcourse\n WHERE c.id " . $whereclause . " ORDER BY c.sortorder"; $list = $DB->get_records_sql($sql, array('contextcourse' => CONTEXT_COURSE) + $params); $coursestoselect = array(); foreach ($list as $course) { context_helper::preload_from_record($course); // Make sure we can see the course. if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', context_course::instance($course->id))) { continue; } $label = get_course_display_name_for_list($course); $this->addOption($label, $course->id); array_push($coursestoselect, $course->id); } return $this->setSelected($coursestoselect); }
/** * Constructor. * * @param string $uniqueid Unique ID. * @param int $courseid Course ID. * @param int $groupid Group ID. */ public function __construct($uniqueid, $courseid, $groupid, array $options = array(), $userid = null) { global $PAGE, $USER; parent::__construct($uniqueid); if (isset($options['rankmode'])) { $this->rankmode = $options['rankmode']; } if (isset($options['neighboursonly'])) { $this->neighboursonly = $options['neighboursonly']; } if (isset($options['neighboursabove'])) { $this->neighboursabove = $options['neighboursabove']; } if (isset($options['neighboursbelow'])) { $this->neighboursbelow = $options['neighboursbelow']; } if (isset($options['identitymode'])) { $this->identitymode = $options['identitymode']; } // The user ID we're viewing the ladder for. if ($userid === null) { $userid = $USER->id; } $this->userid = $userid; // Block XP stuff. $this->xpmanager = block_xp_manager::get($courseid); $this->xpoutput = $PAGE->get_renderer('block_xp'); // Define columns, and headers. $columns = array(); $headers = array(); if ($this->rankmode != block_xp_manager::RANK_OFF) { $columns += array('rank'); if ($this->rankmode == block_xp_manager::RANK_REL) { $headers += array(get_string('difference', 'block_xp')); } else { $headers += array(get_string('rank', 'block_xp')); } } $columns = array_merge($columns, array('userpic', 'fullname', 'lvl', 'xp', 'progress')); $headers = array_merge($headers, array('', get_string('fullname'), get_string('level', 'block_xp'), get_string('xp', 'block_xp'), get_string('progress', 'block_xp'))); $this->define_columns($columns); $this->define_headers($headers); // Define SQL. $sqlfrom = ''; $sqlparams = array(); if ($groupid) { $sqlfrom = '{block_xp} x JOIN {groups_members} gm ON gm.groupid = :groupid AND gm.userid = x.userid JOIN {user} u ON x.userid = u.id'; $sqlparams = array('groupid' => $groupid); } else { $sqlfrom = '{block_xp} x JOIN {user} u ON x.userid = u.id'; } $sqlfrom .= " JOIN {context} ctx\n ON ctx.instanceid = u.id\n AND ctx.contextlevel = :contextlevel"; $sqlparams += array('contextlevel' => CONTEXT_USER); $this->sql = new stdClass(); $this->sql->fields = 'x.*, ' . user_picture::fields('u', null, 'userid') . ', ' . context_helper::get_preload_record_columns_sql('ctx'); $this->sql->from = $sqlfrom; $this->sql->where = 'courseid = :courseid'; $this->sql->params = array_merge(array('courseid' => $courseid), $sqlparams); // Define various table settings. $this->sortable(false); $this->no_sorting('userpic'); $this->no_sorting('progress'); $this->collapsible(false); }
/** * This function gets called by {@link settings_navigation::load_user_settings()} and actually works out * what can be shown/done * * @param int $courseid The current course' id * @param int $userid The user id to load for * @param string $gstitle The string to pass to get_string for the branch title * @return navigation_node|false */ protected function generate_user_settings($courseid, $userid, $gstitle = 'usercurrentsettings') { global $DB, $CFG, $USER, $SITE; if ($courseid != $SITE->id) { if (!empty($this->page->course->id) && $this->page->course->id == $courseid) { $course = $this->page->course; } else { $select = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT c.*, {$select}\n FROM {course} c\n JOIN {context} ctx ON c.id = ctx.instanceid\n WHERE c.id = :courseid AND ctx.contextlevel = :contextlevel"; $params = array('courseid' => $courseid, 'contextlevel' => CONTEXT_COURSE); $course = $DB->get_record_sql($sql, $params, MUST_EXIST); context_helper::preload_from_record($course); } } else { $course = $SITE; } $coursecontext = context_course::instance($course->id); // Course context $systemcontext = context_system::instance(); $currentuser = $USER->id == $userid; if ($currentuser) { $user = $USER; $usercontext = context_user::instance($user->id); // User context } else { $select = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT u.*, {$select}\n FROM {user} u\n JOIN {context} ctx ON u.id = ctx.instanceid\n WHERE u.id = :userid AND ctx.contextlevel = :contextlevel"; $params = array('userid' => $userid, 'contextlevel' => CONTEXT_USER); $user = $DB->get_record_sql($sql, $params, IGNORE_MISSING); if (!$user) { return false; } context_helper::preload_from_record($user); // Check that the user can view the profile $usercontext = context_user::instance($user->id); // User context $canviewuser = has_capability('moodle/user:viewdetails', $usercontext); if ($course->id == $SITE->id) { if ($CFG->forceloginforprofiles && !has_coursecontact_role($user->id) && !$canviewuser) { // Reduce possibility of "browsing" userbase at site level // Teachers can browse and be browsed at site level. If not forceloginforprofiles, allow access (bug #4366) return false; } } else { $canviewusercourse = has_capability('moodle/user:viewdetails', $coursecontext); $userisenrolled = is_enrolled($coursecontext, $user->id, '', true); if (!$canviewusercourse && !$canviewuser || !$userisenrolled) { return false; } $canaccessallgroups = has_capability('moodle/site:accessallgroups', $coursecontext); if (!$canaccessallgroups && groups_get_course_groupmode($course) == SEPARATEGROUPS && !$canviewuser) { // If groups are in use, make sure we can see that group (MDL-45874). That does not apply to parents. if ($courseid == $this->page->course->id) { $mygroups = get_fast_modinfo($this->page->course)->groups; } else { $mygroups = groups_get_user_groups($courseid); } $usergroups = groups_get_user_groups($courseid, $userid); if (!array_intersect_key($mygroups[0], $usergroups[0])) { return false; } } } } $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $this->page->context)); $key = $gstitle; $prefurl = new moodle_url('/user/preferences.php'); if ($gstitle != 'usercurrentsettings') { $key .= $userid; $prefurl->param('userid', $userid); } // Add a user setting branch. if ($gstitle == 'usercurrentsettings') { $dashboard = $this->add(get_string('myhome'), new moodle_url('/my/'), self::TYPE_CONTAINER, null, 'dashboard'); // This should be set to false as we don't want to show this to the user. It's only for generating the correct // breadcrumb. $dashboard->display = false; if (get_home_page() == HOMEPAGE_MY) { $dashboard->mainnavonly = true; } $iscurrentuser = $user->id == $USER->id; $baseargs = array('id' => $user->id); if ($course->id != $SITE->id && !$iscurrentuser) { $baseargs['course'] = $course->id; $issitecourse = false; } else { // Load all categories and get the context for the system. $issitecourse = true; } // Add the user profile to the dashboard. $profilenode = $dashboard->add(get_string('profile'), new moodle_url('/user/profile.php', array('id' => $user->id)), self::TYPE_SETTING, null, 'myprofile'); if (!empty($CFG->navadduserpostslinks)) { // Add nodes for forum posts and discussions if the user can view either or both // There are no capability checks here as the content of the page is based // purely on the forums the current user has access too. $forumtab = $profilenode->add(get_string('forumposts', 'forum')); $forumtab->add(get_string('posts', 'forum'), new moodle_url('/mod/forum/user.php', $baseargs), null, 'myposts'); $forumtab->add(get_string('discussions', 'forum'), new moodle_url('/mod/forum/user.php', array_merge($baseargs, array('mode' => 'discussions'))), null, 'mydiscussions'); } // Add blog nodes. if (!empty($CFG->enableblogs)) { if (!$this->cache->cached('userblogoptions' . $user->id)) { require_once $CFG->dirroot . '/blog/lib.php'; // Get all options for the user. $options = blog_get_options_for_user($user); $this->cache->set('userblogoptions' . $user->id, $options); } else { $options = $this->cache->{'userblogoptions' . $user->id}; } if (count($options) > 0) { $blogs = $profilenode->add(get_string('blogs', 'blog'), null, navigation_node::TYPE_CONTAINER); foreach ($options as $type => $option) { if ($type == "rss") { $blogs->add($option['string'], $option['link'], self::TYPE_SETTING, null, null, new pix_icon('i/rss', '')); } else { $blogs->add($option['string'], $option['link'], self::TYPE_SETTING, null, 'blog' . $type); } } } } // Add the messages link. // It is context based so can appear in the user's profile and in course participants information. if (!empty($CFG->messaging)) { $messageargs = array('user1' => $USER->id); if ($USER->id != $user->id) { $messageargs['user2'] = $user->id; } if ($course->id != $SITE->id) { $messageargs['viewing'] = MESSAGE_VIEW_COURSE . $course->id; } $url = new moodle_url('/message/index.php', $messageargs); $dashboard->add(get_string('messages', 'message'), $url, self::TYPE_SETTING, null, 'messages'); } // Add the "My private files" link. // This link doesn't have a unique display for course context so only display it under the user's profile. if ($issitecourse && $iscurrentuser && has_capability('moodle/user:manageownfiles', $usercontext)) { $url = new moodle_url('/user/files.php'); $dashboard->add(get_string('privatefiles'), $url, self::TYPE_SETTING); } // Add a node to view the users notes if permitted. if (!empty($CFG->enablenotes) && has_any_capability(array('moodle/notes:manage', 'moodle/notes:view'), $coursecontext)) { $url = new moodle_url('/notes/index.php', array('user' => $user->id)); if ($coursecontext->instanceid != SITEID) { $url->param('course', $coursecontext->instanceid); } $profilenode->add(get_string('notes', 'notes'), $url); } // Show the grades node. if ($issitecourse && $iscurrentuser || has_capability('moodle/user:viewdetails', $usercontext)) { require_once $CFG->dirroot . '/user/lib.php'; // Set the grades node to link to the "Grades" page. if ($course->id == SITEID) { $url = user_mygrades_url($user->id, $course->id); } else { // Otherwise we are in a course and should redirect to the user grade report (Activity report version). $url = new moodle_url('/course/user.php', array('mode' => 'grade', 'id' => $course->id, 'user' => $user->id)); } $dashboard->add(get_string('grades', 'grades'), $url, self::TYPE_SETTING, null, 'mygrades'); } // Let plugins hook into user navigation. $pluginsfunction = get_plugins_with_function('extend_navigation_user', 'lib.php'); foreach ($pluginsfunction as $plugintype => $plugins) { if ($plugintype != 'report') { foreach ($plugins as $pluginfunction) { $pluginfunction($profilenode, $user, $usercontext, $course, $coursecontext); } } } $usersetting = navigation_node::create(get_string('preferences', 'moodle'), $prefurl, self::TYPE_CONTAINER, null, $key); $dashboard->add_node($usersetting); } else { $usersetting = $this->add(get_string('preferences', 'moodle'), $prefurl, self::TYPE_CONTAINER, null, $key); $usersetting->display = false; } $usersetting->id = 'usersettings'; // Check if the user has been deleted. if ($user->deleted) { if (!has_capability('moodle/user:update', $coursecontext)) { // We can't edit the user so just show the user deleted message. $usersetting->add(get_string('userdeleted'), null, self::TYPE_SETTING); } else { // We can edit the user so show the user deleted message and link it to the profile. if ($course->id == $SITE->id) { $profileurl = new moodle_url('/user/profile.php', array('id' => $user->id)); } else { $profileurl = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id)); } $usersetting->add(get_string('userdeleted'), $profileurl, self::TYPE_SETTING); } return true; } $userauthplugin = false; if (!empty($user->auth)) { $userauthplugin = get_auth_plugin($user->auth); } $useraccount = $usersetting->add(get_string('useraccount'), null, self::TYPE_CONTAINER, null, 'useraccount'); // Add the profile edit link. if (isloggedin() && !isguestuser($user) && !is_mnet_remote_user($user)) { if (($currentuser || is_siteadmin($USER) || !is_siteadmin($user)) && has_capability('moodle/user:update', $systemcontext)) { $url = new moodle_url('/user/editadvanced.php', array('id' => $user->id, 'course' => $course->id)); $useraccount->add(get_string('editmyprofile'), $url, self::TYPE_SETTING); } else { if (has_capability('moodle/user:editprofile', $usercontext) && !is_siteadmin($user) || $currentuser && has_capability('moodle/user:editownprofile', $systemcontext)) { if ($userauthplugin && $userauthplugin->can_edit_profile()) { $url = $userauthplugin->edit_profile_url(); if (empty($url)) { $url = new moodle_url('/user/edit.php', array('id' => $user->id, 'course' => $course->id)); } $useraccount->add(get_string('editmyprofile'), $url, self::TYPE_SETTING); } } } } // Change password link. if ($userauthplugin && $currentuser && !\core\session\manager::is_loggedinas() && !isguestuser() && has_capability('moodle/user:changeownpassword', $systemcontext) && $userauthplugin->can_change_password()) { $passwordchangeurl = $userauthplugin->change_password_url(); if (empty($passwordchangeurl)) { $passwordchangeurl = new moodle_url('/login/change_password.php', array('id' => $course->id)); } $useraccount->add(get_string("changepassword"), $passwordchangeurl, self::TYPE_SETTING, null, 'changepassword'); } if (isloggedin() && !isguestuser($user) && !is_mnet_remote_user($user)) { if ($currentuser && has_capability('moodle/user:editownprofile', $systemcontext) || has_capability('moodle/user:editprofile', $usercontext)) { $url = new moodle_url('/user/language.php', array('id' => $user->id, 'course' => $course->id)); $useraccount->add(get_string('preferredlanguage'), $url, self::TYPE_SETTING, null, 'preferredlanguage'); } } $pluginmanager = core_plugin_manager::instance(); $enabled = $pluginmanager->get_enabled_plugins('mod'); if (isset($enabled['forum']) && isloggedin() && !isguestuser($user) && !is_mnet_remote_user($user)) { if ($currentuser && has_capability('moodle/user:editownprofile', $systemcontext) || has_capability('moodle/user:editprofile', $usercontext)) { $url = new moodle_url('/user/forum.php', array('id' => $user->id, 'course' => $course->id)); $useraccount->add(get_string('forumpreferences'), $url, self::TYPE_SETTING); } } $editors = editors_get_enabled(); if (count($editors) > 1) { if (isloggedin() && !isguestuser($user) && !is_mnet_remote_user($user)) { if ($currentuser && has_capability('moodle/user:editownprofile', $systemcontext) || has_capability('moodle/user:editprofile', $usercontext)) { $url = new moodle_url('/user/editor.php', array('id' => $user->id, 'course' => $course->id)); $useraccount->add(get_string('editorpreferences'), $url, self::TYPE_SETTING); } } } // Add "Course preferences" link. if (isloggedin() && !isguestuser($user)) { if ($currentuser && has_capability('moodle/user:editownprofile', $systemcontext) || has_capability('moodle/user:editprofile', $usercontext)) { $url = new moodle_url('/user/course.php', array('id' => $user->id, 'course' => $course->id)); $useraccount->add(get_string('coursepreferences'), $url, self::TYPE_SETTING, null, 'coursepreferences'); } } // View the roles settings. if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override', 'moodle/role:manage'), $usercontext)) { $roles = $usersetting->add(get_string('roles'), null, self::TYPE_SETTING); $url = new moodle_url('/admin/roles/usersroles.php', array('userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('thisusersroles', 'role'), $url, self::TYPE_SETTING); $assignableroles = get_assignable_roles($usercontext, ROLENAME_BOTH); if (!empty($assignableroles)) { $url = new moodle_url('/admin/roles/assign.php', array('contextid' => $usercontext->id, 'userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('assignrolesrelativetothisuser', 'role'), $url, self::TYPE_SETTING); } if (has_capability('moodle/role:review', $usercontext) || count(get_overridable_roles($usercontext, ROLENAME_BOTH)) > 0) { $url = new moodle_url('/admin/roles/permissions.php', array('contextid' => $usercontext->id, 'userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('permissions', 'role'), $url, self::TYPE_SETTING); } $url = new moodle_url('/admin/roles/check.php', array('contextid' => $usercontext->id, 'userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING); } // Repositories. if (!$this->cache->cached('contexthasrepos' . $usercontext->id)) { require_once $CFG->dirroot . '/repository/lib.php'; $editabletypes = repository::get_editable_types($usercontext); $haseditabletypes = !empty($editabletypes); unset($editabletypes); $this->cache->set('contexthasrepos' . $usercontext->id, $haseditabletypes); } else { $haseditabletypes = $this->cache->{'contexthasrepos' . $usercontext->id}; } if ($haseditabletypes) { $repositories = $usersetting->add(get_string('repositories', 'repository'), null, self::TYPE_SETTING); $repositories->add(get_string('manageinstances', 'repository'), new moodle_url('/repository/manage_instances.php', array('contextid' => $usercontext->id))); } // Portfolio. if ($currentuser && !empty($CFG->enableportfolios) && has_capability('moodle/portfolio:export', $systemcontext)) { require_once $CFG->libdir . '/portfoliolib.php'; if (portfolio_has_visible_instances()) { $portfolio = $usersetting->add(get_string('portfolios', 'portfolio'), null, self::TYPE_SETTING); $url = new moodle_url('/user/portfolio.php', array('courseid' => $course->id)); $portfolio->add(get_string('configure', 'portfolio'), $url, self::TYPE_SETTING); $url = new moodle_url('/user/portfoliologs.php', array('courseid' => $course->id)); $portfolio->add(get_string('logs', 'portfolio'), $url, self::TYPE_SETTING); } } $enablemanagetokens = false; if (!empty($CFG->enablerssfeeds)) { $enablemanagetokens = true; } else { if (!is_siteadmin($USER->id) && !empty($CFG->enablewebservices) && has_capability('moodle/webservice:createtoken', context_system::instance())) { $enablemanagetokens = true; } } // Security keys. if ($currentuser && $enablemanagetokens) { $url = new moodle_url('/user/managetoken.php', array('sesskey' => sesskey())); $useraccount->add(get_string('securitykeys', 'webservice'), $url, self::TYPE_SETTING); } // Messaging. if ($currentuser && has_capability('moodle/user:editownmessageprofile', $systemcontext) || !isguestuser($user) && has_capability('moodle/user:editmessageprofile', $usercontext) && !is_primary_admin($user->id)) { $url = new moodle_url('/message/edit.php', array('id' => $user->id)); $useraccount->add(get_string('messaging', 'message'), $url, self::TYPE_SETTING); } // Blogs. if ($currentuser && !empty($CFG->enableblogs)) { $blog = $usersetting->add(get_string('blogs', 'blog'), null, navigation_node::TYPE_CONTAINER, null, 'blogs'); if (has_capability('moodle/blog:view', $systemcontext)) { $blog->add(get_string('preferences', 'blog'), new moodle_url('/blog/preferences.php'), navigation_node::TYPE_SETTING); } if (!empty($CFG->useexternalblogs) && $CFG->maxexternalblogsperuser > 0 && has_capability('moodle/blog:manageexternal', $systemcontext)) { $blog->add(get_string('externalblogs', 'blog'), new moodle_url('/blog/external_blogs.php'), navigation_node::TYPE_SETTING); $blog->add(get_string('addnewexternalblog', 'blog'), new moodle_url('/blog/external_blog_edit.php'), navigation_node::TYPE_SETTING); } // Remove the blog node if empty. $blog->trim_if_empty(); } // Badges. if ($currentuser && !empty($CFG->enablebadges)) { $badges = $usersetting->add(get_string('badges'), null, navigation_node::TYPE_CONTAINER, null, 'badges'); if (has_capability('moodle/badges:manageownbadges', $usercontext)) { $url = new moodle_url('/badges/mybadges.php'); $badges->add(get_string('managebadges', 'badges'), $url, self::TYPE_SETTING); } $badges->add(get_string('preferences', 'badges'), new moodle_url('/badges/preferences.php'), navigation_node::TYPE_SETTING); if (!empty($CFG->badges_allowexternalbackpack)) { $badges->add(get_string('backpackdetails', 'badges'), new moodle_url('/badges/mybackpack.php'), navigation_node::TYPE_SETTING); } } // Let plugins hook into user settings navigation. $pluginsfunction = get_plugins_with_function('extend_navigation_user_settings', 'lib.php'); foreach ($pluginsfunction as $plugintype => $plugins) { foreach ($plugins as $pluginfunction) { $pluginfunction($usersetting, $user, $usercontext, $course, $coursecontext); } } return $usersetting; }
/** * This method actually loads the blocks for our page from the database. * * @param boolean|null $includeinvisible * null (default) - load hidden blocks if $this->page->user_is_editing(); * true - load hidden blocks. * false - don't load hidden blocks. */ public function load_blocks($includeinvisible = null) { global $DB, $CFG; if (!is_null($this->birecordsbyregion)) { // Already done. return; } if ($CFG->version < 2009050619) { // Upgrade/install not complete. Don't try too show any blocks. $this->birecordsbyregion = array(); return; } // Ensure we have been initialised. if (is_null($this->defaultregion)) { $this->page->initialise_theme_and_output(); // If there are still no block regions, then there are no blocks on this page. if (empty($this->regions)) { $this->birecordsbyregion = array(); return; } } // Check if we need to load normal blocks if ($this->fakeblocksonly) { $this->birecordsbyregion = $this->prepare_per_region_arrays(); return; } if (is_null($includeinvisible)) { $includeinvisible = $this->page->user_is_editing(); } if ($includeinvisible) { $visiblecheck = ''; } else { $visiblecheck = 'AND (bp.visible = 1 OR bp.visible IS NULL)'; } $context = $this->page->context; $contexttest = 'bi.parentcontextid IN (:contextid2, :contextid3)'; $parentcontextparams = array(); $parentcontextids = $context->get_parent_context_ids(); if ($parentcontextids) { list($parentcontexttest, $parentcontextparams) = $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED, 'parentcontext'); $contexttest = "({$contexttest} OR (bi.showinsubcontexts = 1 AND bi.parentcontextid {$parentcontexttest}))"; } $pagetypepatterns = matching_page_type_patterns($this->page->pagetype); list($pagetypepatterntest, $pagetypepatternparams) = $DB->get_in_or_equal($pagetypepatterns, SQL_PARAMS_NAMED, 'pagetypepatterntest'); $ccselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = bi.id AND ctx.contextlevel = :contextlevel)"; $systemcontext = context_system::instance(); $params = array('contextlevel' => CONTEXT_BLOCK, 'subpage1' => $this->page->subpage, 'subpage2' => $this->page->subpage, 'contextid1' => $context->id, 'contextid2' => $context->id, 'contextid3' => $systemcontext->id, 'pagetype' => $this->page->pagetype); if ($this->page->subpage === '') { $params['subpage1'] = ''; $params['subpage2'] = ''; } $sql = "SELECT\n bi.id,\n bp.id AS blockpositionid,\n bi.blockname,\n bi.parentcontextid,\n bi.showinsubcontexts,\n bi.pagetypepattern,\n bi.subpagepattern,\n bi.defaultregion,\n bi.defaultweight,\n COALESCE(bp.visible, 1) AS visible,\n COALESCE(bp.region, bi.defaultregion) AS region,\n COALESCE(bp.weight, bi.defaultweight) AS weight,\n bi.configdata\n {$ccselect}\n\n FROM {block_instances} bi\n JOIN {block} b ON bi.blockname = b.name\n LEFT JOIN {block_positions} bp ON bp.blockinstanceid = bi.id\n AND bp.contextid = :contextid1\n AND bp.pagetype = :pagetype\n AND bp.subpage = :subpage1\n {$ccjoin}\n\n WHERE\n {$contexttest}\n AND bi.pagetypepattern {$pagetypepatterntest}\n AND (bi.subpagepattern IS NULL OR bi.subpagepattern = :subpage2)\n {$visiblecheck}\n AND b.visible = 1\n\n ORDER BY\n COALESCE(bp.region, bi.defaultregion),\n COALESCE(bp.weight, bi.defaultweight),\n bi.id"; $blockinstances = $DB->get_recordset_sql($sql, $params + $parentcontextparams + $pagetypepatternparams); $this->birecordsbyregion = $this->prepare_per_region_arrays(); $unknown = array(); foreach ($blockinstances as $bi) { context_helper::preload_from_record($bi); if ($this->is_known_region($bi->region)) { $this->birecordsbyregion[$bi->region][] = $bi; } else { $unknown[] = $bi; } } // Pages don't necessarily have a defaultregion. The one time this can // happen is when there are no theme block regions, but the script itself // has a block region in the main content area. if (!empty($this->defaultregion)) { $this->birecordsbyregion[$this->defaultregion] = array_merge($this->birecordsbyregion[$this->defaultregion], $unknown); } }
/** * Gets all of the courses where the provided user has posted in a forum. * * @global moodle_database $DB The database connection * @param stdClass $user The user who's posts we are looking for * @param bool $discussionsonly If true only look for discussions started by the user * @param bool $includecontexts If set to trye contexts for the courses will be preloaded * @param int $limitfrom The offset of records to return * @param int $limitnum The number of records to return * @return array An array of courses */ function forum_get_courses_user_posted_in($user, $discussionsonly = false, $includecontexts = true, $limitfrom = null, $limitnum = null) { global $DB; // If we are only after discussions we need only look at the forum_discussions // table and join to the userid there. If we are looking for posts then we need // to join to the forum_posts table. if (!$discussionsonly) { $subquery = "(SELECT DISTINCT fd.course\n FROM {forum_discussions} fd\n JOIN {forum_posts} fp ON fp.discussion = fd.id\n WHERE fp.userid = :userid )"; } else { $subquery = "(SELECT DISTINCT fd.course\n FROM {forum_discussions} fd\n WHERE fd.userid = :userid )"; } $params = array('userid' => $user->id); // Join to the context table so that we can preload contexts if required. if ($includecontexts) { $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; $params['contextlevel'] = CONTEXT_COURSE; } else { $ctxselect = ''; $ctxjoin = ''; } // Now we need to get all of the courses to search. // All courses where the user has posted within a forum will be returned. $sql = "SELECT c.* {$ctxselect}\n FROM {course} c\n {$ctxjoin}\n WHERE c.id IN ({$subquery})"; $courses = $DB->get_records_sql($sql, $params, $limitfrom, $limitnum); if ($includecontexts) { array_map('context_helper::preload_from_record', $courses); } return $courses; }
/** * Helper function to create list of user fullnames shown in log report. * * This will update $this->userfullnames array with userfullname, * which will be used to render logs in table. * * @since Moodle 2.9 * @return void protected function update_users_used() { global $DB; $this->userfullnames = array(); $userids = array(); // For each event cache full username. // Get list of userids which will be shown in log report. foreach ($this->rawdata as $event) { $logextra = $event->get_logextra(); if (!empty($event->userid) && empty($userids[$event->userid])) { $userids[$event->userid] = $event->userid; } if (!empty($logextra['realuserid']) && empty($userids[$logextra['realuserid']])) { $userids[$logextra['realuserid']] = $logextra['realuserid']; } if (!empty($event->relateduserid) && empty($userids[$event->relateduserid])) { $userids[$event->relateduserid] = $event->relateduserid; } } // Get user fullname and put that in return list. if (!empty($userids)) { list($usql, $uparams) = $DB->get_in_or_equal($userids); $users = $DB->get_records_sql("SELECT id," . get_all_user_name_fields(true) . " FROM {user} WHERE id " . $usql, $uparams); foreach ($users as $userid => $user) { $this->userfullnames[$userid] = fullname($user); unset($userids[$userid]); } // We fill the array with false values for the users that don't exist anymore // in the database so we don't need to query the db again later. foreach ($userids as $userid) { $this->userfullnames[$userid] = false; } } } */ protected function update_users_used() { global $SITE, $DB; $this->userfullnames = array(); $this->courseshortnames = array($SITE->id => $SITE->shortname); $userids = array(); $courseids = array(); // For each event cache full username and course. // Get list of userids and courseids which will be shown in log report. foreach ($this->rawdata as $event) { $logextra = $event->get_logextra(); if (!empty($event->userid) && empty($userids[$event->userid])) { $userids[$event->userid] = $event->userid; } if (!empty($logextra['realuserid']) && empty($userids[$logextra['realuserid']])) { $userids[$logextra['realuserid']] = $logextra['realuserid']; } if (!empty($event->relateduserid) && empty($userids[$event->relateduserid])) { $userids[$event->relateduserid] = $event->relateduserid; } if (!empty($event->courseid) && $event->courseid != $SITE->id && !in_array($event->courseid, $courseids)) { $courseids[] = $event->courseid; } } // Closing it just in case, we can not rewind moodle recordsets anyway. if ($this->rawdata instanceof \core\dml\recordset_walk || $this->rawdata instanceof moodle_recordset) { $this->rawdata->close(); } // Get user fullname and put that in return list. if (!empty($userids)) { list($usql, $uparams) = $DB->get_in_or_equal($userids); $users = $DB->get_records_sql("SELECT id," . get_all_user_name_fields(true) . " FROM {user} WHERE id " . $usql, $uparams); foreach ($users as $userid => $user) { $this->userfullnames[$userid] = fullname($user); unset($userids[$userid]); } // We fill the array with false values for the users that don't exist anymore // in the database so we don't need to query the db again later. foreach ($userids as $userid) { $this->userfullnames[$userid] = false; } } // Get course shortname and put that in return list. if (!empty($courseids)) { // If all logs don't belong to site level then get course info. list($coursesql, $courseparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED); $ccselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $courseparams['contextlevel'] = CONTEXT_COURSE; $sql = "\n SELECT\n c.id, c.shortname {$ccselect}\n FROM\n {course} c\n LEFT JOIN\n {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)\n WHERE\n c.id " . $coursesql; // A response code other than 0 is a failure $courses = $DB->get_records_sql($sql, $courseparams); foreach ($courses as $courseid => $course) { $url = new moodle_url("/course/view.php", array('id' => $courseid)); context_helper::preload_from_record($course); $context = context_course::instance($courseid, IGNORE_MISSING); // Method format_string() takes care of missing contexts. $this->courseshortnames[$courseid] = html_writer::link($url, format_string($course->shortname, true, array('context' => $context))); } } }
/** * A list of courses that match a search * * @global object * @global object * @param array $searchterms An array of search criteria * @param string $sort A field and direction to sort by * @param int $page The page number to get * @param int $recordsperpage The number of records per page * @param int $totalcount Passed in by reference. * @param array $requiredcapabilities Extra list of capabilities used to filter courses * @return object {@link $COURSE} records */ function get_courses_search($searchterms, $sort, $page, $recordsperpage, &$totalcount, $requiredcapabilities = array()) { global $CFG, $DB; if ($DB->sql_regex_supported()) { $REGEXP = $DB->sql_regex(true); $NOTREGEXP = $DB->sql_regex(false); } $searchcond = array(); $params = array(); $i = 0; // Thanks Oracle for your non-ansi concat and type limits in coalesce. MDL-29912 if ($DB->get_dbfamily() == 'oracle') { $concat = "(c.summary|| ' ' || c.fullname || ' ' || c.idnumber || ' ' || c.shortname)"; } else { $concat = $DB->sql_concat("COALESCE(c.summary, '')", "' '", 'c.fullname', "' '", 'c.idnumber', "' '", 'c.shortname'); } foreach ($searchterms as $searchterm) { $i++; $NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle /// will use it to simulate the "-" operator with LIKE clause /// Under Oracle and MSSQL, trim the + and - operators and perform /// simpler LIKE (or NOT LIKE) queries if (!$DB->sql_regex_supported()) { if (substr($searchterm, 0, 1) == '-') { $NOT = true; } $searchterm = trim($searchterm, '+-'); } // TODO: +- may not work for non latin languages if (substr($searchterm, 0, 1) == '+') { $searchterm = trim($searchterm, '+-'); $searchterm = preg_quote($searchterm, '|'); $searchcond[] = "{$concat} {$REGEXP} :ss{$i}"; $params['ss' . $i] = "(^|[^a-zA-Z0-9]){$searchterm}([^a-zA-Z0-9]|\$)"; } else { if (substr($searchterm, 0, 1) == "-") { $searchterm = trim($searchterm, '+-'); $searchterm = preg_quote($searchterm, '|'); $searchcond[] = "{$concat} {$NOTREGEXP} :ss{$i}"; $params['ss' . $i] = "(^|[^a-zA-Z0-9]){$searchterm}([^a-zA-Z0-9]|\$)"; } else { $searchcond[] = $DB->sql_like($concat, ":ss{$i}", false, true, $NOT); $params['ss' . $i] = "%{$searchterm}%"; } } } if (empty($searchcond)) { $searchcond = array('1 = 1'); } $searchcond = implode(" AND ", $searchcond); $courses = array(); $c = 0; // counts how many visible courses we've seen // Tiki pagination $limitfrom = $page * $recordsperpage; $limitto = $limitfrom + $recordsperpage; $ccselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; $params['contextlevel'] = CONTEXT_COURSE; $sql = "SELECT c.* {$ccselect}\n FROM {course} c\n {$ccjoin}\n WHERE {$searchcond} AND c.id <> " . SITEID . "\n ORDER BY {$sort}"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $course) { // Preload contexts only for hidden courses or courses we need to return. context_helper::preload_from_record($course); $coursecontext = context_course::instance($course->id); if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { continue; } if (!empty($requiredcapabilities)) { if (!has_all_capabilities($requiredcapabilities, $coursecontext)) { continue; } } // Don't exit this loop till the end // we need to count all the visible courses // to update $totalcount if ($c >= $limitfrom && $c < $limitto) { $courses[$course->id] = $course; } $c++; } $rs->close(); // our caller expects 2 bits of data - our return // array, and an updated $totalcount $totalcount = $c; return $courses; }
/** * Returns an array of grades calculated by aggregating item ratings. * * @param stdClass $options { * userid => int the id of the user whose items have been rated. NOT the user who submitted the ratings. 0 to update all. [required] * aggregationmethod => int the aggregation method to apply when calculating grades ie RATING_AGGREGATE_AVERAGE [required] * scaleid => int the scale from which the user can select a rating. Used for bounds checking. [required] * itemtable => int the table containing the items [required] * itemtableusercolum => int the column of the user table containing the item owner's user id [required] * component => The component for the ratings [required] * ratingarea => The ratingarea for the ratings [required] * contextid => int the context in which the rated items exist [optional] * modulename => string the name of the module [optional] * moduleid => int the id of the module instance [optional] * } * @return array the array of the user's grades */ public function get_user_grades($options) { global $DB; $contextid = null; if (!isset($options->component)) { throw new coding_exception('The component option is now a required option when getting user grades from ratings.'); } if (!isset($options->ratingarea)) { throw new coding_exception('The ratingarea option is now a required option when getting user grades from ratings.'); } //if the calling code doesn't supply a context id we'll have to figure it out if (!empty($options->contextid)) { $contextid = $options->contextid; } else { if (!empty($options->cmid)) { //not implemented as not currently used although cmid is potentially available (the forum supplies it) //Is there a convenient way to get a context id from a cm id? //$cmidnumber = $options->cmidnumber; } else { if (!empty($options->modulename) && !empty($options->moduleid)) { $modulename = $options->modulename; $moduleid = intval($options->moduleid); // Going direct to the db for the context id seems wrong. $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = cm.id AND ctx.contextlevel = :contextlevel)"; $sql = "SELECT cm.* {$ctxselect}\n FROM {course_modules} cm\n LEFT JOIN {modules} mo ON mo.id = cm.module\n LEFT JOIN {{$modulename}} m ON m.id = cm.instance {$ctxjoin}\n WHERE mo.name=:modulename AND\n m.id=:moduleid"; $params = array('modulename' => $modulename, 'moduleid' => $moduleid, 'contextlevel' => CONTEXT_MODULE); $contextrecord = $DB->get_record_sql($sql, $params, '*', MUST_EXIST); $contextid = $contextrecord->ctxid; } } } $params = array(); $params['contextid'] = $contextid; $params['component'] = $options->component; $params['ratingarea'] = $options->ratingarea; $itemtable = $options->itemtable; $itemtableusercolumn = $options->itemtableusercolumn; $scaleid = $options->scaleid; $aggregationstring = $this->get_aggregation_method($options->aggregationmethod); //if userid is not 0 we only want the grade for a single user $singleuserwhere = ''; if ($options->userid != 0) { $params['userid1'] = intval($options->userid); $singleuserwhere = "AND i.{$itemtableusercolumn} = :userid1"; } //MDL-24648 The where line used to be "WHERE (r.contextid is null or r.contextid=:contextid)" //r.contextid will be null for users who haven't been rated yet //no longer including users who haven't been rated to reduce memory requirements $sql = "SELECT u.id as id, u.id AS userid, {$aggregationstring}(r.rating) AS rawgrade\n FROM {user} u\n LEFT JOIN {{$itemtable}} i ON u.id=i.{$itemtableusercolumn}\n LEFT JOIN {rating} r ON r.itemid=i.id\n WHERE r.contextid = :contextid AND\n r.component = :component AND\n r.ratingarea = :ratingarea\n {$singleuserwhere}\n GROUP BY u.id"; $results = $DB->get_records_sql($sql, $params); if ($results) { $scale = null; $max = 0; if ($options->scaleid >= 0) { //numeric $max = $options->scaleid; } else { //custom scales $scale = $DB->get_record('scale', array('id' => -$options->scaleid)); if ($scale) { $scale = explode(',', $scale->scale); $max = count($scale); } else { debugging('rating_manager::get_user_grades() received a scale ID that doesnt exist'); } } // it could throw off the grading if count and sum returned a rawgrade higher than scale // so to prevent it we review the results and ensure that rawgrade does not exceed the scale, if it does we set rawgrade = scale (i.e. full credit) foreach ($results as $rid => $result) { if ($options->scaleid >= 0) { //numeric if ($result->rawgrade > $options->scaleid) { $results[$rid]->rawgrade = $options->scaleid; } } else { //scales if (!empty($scale) && $result->rawgrade > $max) { $results[$rid]->rawgrade = $max; } } } } return $results; }
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require '../../config.php'; require_once "{$CFG->dirroot}/enrol/locallib.php"; require_once "{$CFG->dirroot}/enrol/renderer.php"; $ueid = required_param('ue', PARAM_INT); // user enrolment id $filter = optional_param('ifilter', 0, PARAM_INT); $confirm = optional_param('confirm', false, PARAM_BOOL); // Get the user enrolment object $ue = $DB->get_record('user_enrolments', array('id' => $ueid), '*', MUST_EXIST); // Get the user for whom the enrolment is $user = $DB->get_record('user', array('id' => $ue->userid), '*', MUST_EXIST); // Get the course the enrolment is to //list($ctxsql, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); $ctxsql = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT c.*, {$ctxsql}\n FROM {course} c\n LEFT JOIN {enrol} e ON e.courseid = c.id\n\t\t LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextcourse)\n WHERE e.id = :enrolid"; $params = array('enrolid' => $ue->enrolid, 'contextcourse' => CONTEXT_COURSE); $course = $DB->get_record_sql($sql, $params, MUST_EXIST); context_helper::preload_from_record($course); // Make sure it's not the front page if ($course->id == SITEID) { redirect(new moodle_url('/')); } // Obviously require_login($course); // Make sure the user can unenrol users. require_capability("enrol/apply:unenrol", context_course::instance($course->id)); // Get the enrolment manager for this course $manager = new course_enrolment_manager($PAGE, $course, $filter); // Get an enrolment users table object. Doign this will automatically retrieve the the URL params
function get_all_courses($sort = "c.sortorder DESC", $fields = "c.*") { global $CFG, $DB; require_once $CFG->dirroot . '/lib/accesslib.php'; $where = 'WHERE c.id != 1'; if (empty($sort)) { $sortstatement = ""; } else { $sortstatement = "ORDER BY {$sort}"; } $ccselect = ", " . context_helper::get_preload_record_columns_sql('ctx'); $ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; $sql = "SELECT {$fields} {$ccselect}\n FROM {course} c\n {$ccjoin}\n {$where}\n {$sortstatement}"; $param = array('contextlevel' => CONTEXT_COURSE); return $DB->get_records_sql($sql, $param); }
/** * Resort the courses within this category by the given field. * * @param string $field One of fullname, shortname, idnumber or descending values of each (appended desc) * @param bool $cleanup * @return bool True for success. * @throws coding_exception */ public function resort_courses($field, $cleanup = true) { global $DB; $desc = false; if (substr($field, -4) === "desc") { $desc = true; $field = substr($field, 0, -4); // Remove "desc" from field name. } if ($field !== 'fullname' && $field !== 'shortname' && $field !== 'idnumber' && $field !== 'timecreated') { // This is ultra important as we use $field in an SQL statement below this. throw new coding_exception('Invalid field requested'); } $ctxfields = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT c.id, c.sortorder, c.{$field}, {$ctxfields}\n FROM {course} c\n LEFT JOIN {context} ctx ON ctx.instanceid = c.id\n WHERE ctx.contextlevel = :ctxlevel AND\n c.category = :categoryid"; $params = array('ctxlevel' => CONTEXT_COURSE, 'categoryid' => $this->id); $courses = $DB->get_records_sql($sql, $params); if (count($courses) > 0) { foreach ($courses as $courseid => $course) { context_helper::preload_from_record($course); if ($field === 'idnumber') { $course->sortby = $course->idnumber; } else { // It'll require formatting. $options = array('context' => context_course::instance($course->id)); // We format the string first so that it appears as the user would see it. // This ensures the sorting makes sense to them. However it won't necessarily make // sense to everyone if things like multilang filters are enabled. // We then strip any tags as we don't want things such as image tags skewing the // sort results. $course->sortby = strip_tags(format_string($course->{$field}, true, $options)); } // We set it back here rather than using references as there is a bug with using // references in a foreach before passing as an arg by reference. $courses[$courseid] = $course; } // Sort the courses. core_collator::asort_objects_by_property($courses, 'sortby', core_collator::SORT_NATURAL); if (!empty($desc)) { $courses = array_reverse($courses); } $i = 1; foreach ($courses as $course) { $DB->set_field('course', 'sortorder', $this->sortorder + $i, array('id' => $course->id)); $i++; } if ($cleanup) { // This should not be needed but we do it just to be safe. fix_course_sortorder(); cache_helper::purge_by_event('changesincourse'); } } return true; }
/** * This function returns a nice list representing category tree * for display or to use in a form <select> element * * List is cached for 10 minutes * * For example, if you have a tree of categories like: * Miscellaneous (id = 1) * Subcategory (id = 2) * Sub-subcategory (id = 4) * Other category (id = 3) * Then after calling this function you will have * array(1 => 'Miscellaneous', * 2 => 'Miscellaneous / Subcategory', * 4 => 'Miscellaneous / Subcategory / Sub-subcategory', * 3 => 'Other category'); * * If you specify $requiredcapability, then only categories where the current * user has that capability will be added to $list. * If you only have $requiredcapability in a child category, not the parent, * then the child catgegory will still be included. * * If you specify the option $excludeid, then that category, and all its children, * are omitted from the tree. This is useful when you are doing something like * moving categories, where you do not want to allow people to move a category * to be the child of itself. * * See also {@link make_categories_options()} * * @param string/array $requiredcapability if given, only categories where the current * user has this capability will be returned. Can also be an array of capabilities, * in which case they are all required. * @param integer $excludeid Exclude this category and its children from the lists built. * @param string $separator string to use as a separator between parent and child category. Default ' / ' * @return array of strings */ public static function make_categories_list($requiredcapability = '', $excludeid = 0, $separator = ' / ') { global $DB; $coursecatcache = cache::make('core', 'coursecat'); // Check if we cached the complete list of user-accessible category names ($baselist) or list of ids with requried cap ($thislist). $basecachekey = 'catlist'; $baselist = $coursecatcache->get($basecachekey); if ($baselist !== false) { $baselist = false; } $thislist = false; if (!empty($requiredcapability)) { $requiredcapability = (array) $requiredcapability; $thiscachekey = 'catlist:' . serialize($requiredcapability); if ($baselist !== false && ($thislist = $coursecatcache->get($thiscachekey)) !== false) { $thislist = preg_split('|,|', $thislist, -1, PREG_SPLIT_NO_EMPTY); } } else { if ($baselist !== false) { $thislist = array_keys($baselist); } } if ($baselist === false) { // We don't have $baselist cached, retrieve it. Retrieve $thislist again in any case. $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT cc.id, cc.sortorder, cc.name, cc.visible, cc.parent, cc.path, {$ctxselect}\n FROM {course_categories} cc\n JOIN {context} ctx ON cc.id = ctx.instanceid AND ctx.contextlevel = :contextcoursecat\n ORDER BY cc.sortorder"; $rs = $DB->get_recordset_sql($sql, array('contextcoursecat' => CONTEXT_COURSECAT)); $baselist = array(); $thislist = array(); foreach ($rs as $record) { // If the category's parent is not visible to the user, it is not visible as well. if (!$record->parent || isset($baselist[$record->parent])) { $context = context_coursecat::instance($record->id); if (!$record->visible && !has_capability('moodle/category:viewhiddencategories', $context)) { // No cap to view category, added to neither $baselist nor $thislist continue; } $baselist[$record->id] = array('name' => format_string($record->name, true, array('context' => $context)), 'path' => $record->path); if (!empty($requiredcapability) && !has_all_capabilities($requiredcapability, $context)) { // No required capability, added to $baselist but not to $thislist. continue; } $thislist[] = $record->id; } } $rs->close(); $coursecatcache->set($basecachekey, $baselist); if (!empty($requiredcapability)) { $coursecatcache->set($thiscachekey, join(',', $thislist)); } } else { if ($thislist === false) { // We have $baselist cached but not $thislist. Simplier query is used to retrieve. $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT ctx.instanceid id, {$ctxselect}\n FROM {context} ctx WHERE ctx.contextlevel = :contextcoursecat"; $contexts = $DB->get_records_sql($sql, array('contextcoursecat' => CONTEXT_COURSECAT)); $thislist = array(); foreach (array_keys($baselist) as $id) { context_helper::preload_from_record($contexts[$id]); if (has_all_capabilities($requiredcapability, context_coursecat::instance($id))) { $thislist[] = $id; } } $coursecatcache->set($thiscachekey, join(',', $thislist)); } } // Now build the array of strings to return, mind $separator and $excludeid. $names = array(); foreach ($thislist as $id) { $path = preg_split('|/|', $baselist[$id]['path'], -1, PREG_SPLIT_NO_EMPTY); if (!$excludeid || !in_array($excludeid, $path)) { $namechunks = array(); foreach ($path as $parentid) { $namechunks[] = $baselist[$parentid]['name']; } $names[$id] = join($separator, $namechunks); } } return $names; }
/** * Finds all assignment notifications that have yet to be mailed out, and mails them. * * Cron function to be run periodically according to the moodle cron. * * @return bool */ public static function cron() { global $DB; // Only ever send a max of one days worth of updates. $yesterday = time() - 24 * 3600; $timenow = time(); $lastcron = $DB->get_field('modules', 'lastcron', array('name' => 'assign')); // Collect all submissions that require mailing. // Submissions are included if all are true: // - The assignment is visible in the gradebook. // - No previous notification has been sent. // - If marking workflow is not enabled, the grade was updated in the past 24 hours, or // if marking workflow is enabled, the workflow state is at 'released'. $sql = "SELECT g.id as gradeid, a.course, a.name, a.blindmarking, a.revealidentities,\n g.*, g.timemodified as lastmodified, cm.id as cmid\n FROM {assign} a\n JOIN {assign_grades} g ON g.assignment = a.id\n LEFT JOIN {assign_user_flags} uf ON uf.assignment = a.id AND uf.userid = g.userid\n JOIN {course_modules} cm ON cm.course = a.course AND cm.instance = a.id\n JOIN {modules} md ON md.id = cm.module AND md.name = 'assign'\n JOIN {grade_items} gri ON gri.iteminstance = a.id AND gri.courseid = a.course AND gri.itemmodule = md.name\n WHERE ((a.markingworkflow = 0 AND g.timemodified >= :yesterday AND g.timemodified <= :today) OR\n (a.markingworkflow = 1 AND uf.workflowstate = :wfreleased)) AND\n uf.mailed = 0 AND gri.hidden = 0\n ORDER BY a.course, cm.id"; $params = array('yesterday' => $yesterday, 'today' => $timenow, 'wfreleased' => ASSIGN_MARKING_WORKFLOW_STATE_RELEASED); $submissions = $DB->get_records_sql($sql, $params); if (!empty($submissions)) { mtrace('Processing ' . count($submissions) . ' assignment submissions ...'); // Preload courses we are going to need those. $courseids = array(); foreach ($submissions as $submission) { $courseids[] = $submission->course; } // Filter out duplicates. $courseids = array_unique($courseids); $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); list($courseidsql, $params) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED); $sql = 'SELECT c.*, ' . $ctxselect . ' FROM {course} c LEFT JOIN {context} ctx ON ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel WHERE c.id ' . $courseidsql; $params['contextlevel'] = CONTEXT_COURSE; $courses = $DB->get_records_sql($sql, $params); // Clean up... this could go on for a while. unset($courseids); unset($ctxselect); unset($courseidsql); unset($params); // Message students about new feedback. foreach ($submissions as $submission) { mtrace("Processing assignment submission {$submission->id} ..."); // Do not cache user lookups - could be too many. if (!($user = $DB->get_record('user', array('id' => $submission->userid)))) { mtrace('Could not find user ' . $submission->userid); continue; } // Use a cache to prevent the same DB queries happening over and over. if (!array_key_exists($submission->course, $courses)) { mtrace('Could not find course ' . $submission->course); continue; } $course = $courses[$submission->course]; if (isset($course->ctxid)) { // Context has not yet been preloaded. Do so now. context_helper::preload_from_record($course); } // Override the language and timezone of the "current" user, so that // mail is customised for the receiver. cron_setup_user($user, $course); // Context lookups are already cached. $coursecontext = context_course::instance($course->id); if (!is_enrolled($coursecontext, $user->id)) { $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext)); mtrace(fullname($user) . ' not an active participant in ' . $courseshortname); continue; } if (!($grader = $DB->get_record('user', array('id' => $submission->grader)))) { mtrace('Could not find grader ' . $submission->grader); continue; } $modinfo = get_fast_modinfo($course, $user->id); $cm = $modinfo->get_cm($submission->cmid); // Context lookups are already cached. $contextmodule = context_module::instance($cm->id); if (!$cm->uservisible) { // Hold mail notification for assignments the user cannot access until later. continue; } // Need to send this to the student. $messagetype = 'feedbackavailable'; $eventtype = 'assign_notification'; $updatetime = $submission->lastmodified; $modulename = get_string('modulename', 'assign'); $uniqueid = 0; if ($submission->blindmarking && !$submission->revealidentities) { $uniqueid = self::get_uniqueid_for_user_static($submission->assignment, $user->id); } $showusers = $submission->blindmarking && !$submission->revealidentities; self::send_assignment_notification($grader, $user, $messagetype, $eventtype, $updatetime, $cm, $contextmodule, $course, $modulename, $submission->name, $showusers, $uniqueid); $flags = $DB->get_record('assign_user_flags', array('userid' => $user->id, 'assignment' => $submission->assignment)); if ($flags) { $flags->mailed = 1; $DB->update_record('assign_user_flags', $flags); } else { $flags = new stdClass(); $flags->userid = $user->id; $flags->assignment = $submission->assignment; $flags->mailed = 1; $DB->insert_record('assign_user_flags', $flags); } mtrace('Done'); } mtrace('Done processing ' . count($submissions) . ' assignment submissions'); cron_setup_user(); // Free up memory just to be sure. unset($courses); } // Update calendar events to provide a description. $sql = 'SELECT id FROM {assign} WHERE allowsubmissionsfromdate >= :lastcron AND allowsubmissionsfromdate <= :timenow AND alwaysshowdescription = 0'; $params = array('lastcron' => $lastcron, 'timenow' => $timenow); $newlyavailable = $DB->get_records_sql($sql, $params); foreach ($newlyavailable as $record) { $cm = get_coursemodule_from_instance('assign', $record->id, 0, false, MUST_EXIST); $context = context_module::instance($cm->id); $assignment = new assign($context, null, null); $assignment->update_calendar($cm->id); } return true; }
/** * Get course participants details * * @param int $courseid course id * @param array $options options { * 'name' => option name * 'value' => option value * } * @return array An array of users */ public static function get_enrolled_users($courseid, $options = array()) { global $CFG, $USER, $DB; require_once $CFG->dirroot . "/user/lib.php"; $params = self::validate_parameters(self::get_enrolled_users_parameters(), array('courseid' => $courseid, 'options' => $options)); $withcapability = ''; $groupid = 0; $onlyactive = false; $userfields = array(); $limitfrom = 0; $limitnumber = 0; $sortby = 'us.id'; $sortparams = array(); $sortdirection = 'ASC'; foreach ($options as $option) { switch ($option['name']) { case 'withcapability': $withcapability = $option['value']; break; case 'groupid': $groupid = (int) $option['value']; break; case 'onlyactive': $onlyactive = !empty($option['value']); break; case 'userfields': $thefields = explode(',', $option['value']); foreach ($thefields as $f) { $userfields[] = clean_param($f, PARAM_ALPHANUMEXT); } break; case 'limitfrom': $limitfrom = clean_param($option['value'], PARAM_INT); break; case 'limitnumber': $limitnumber = clean_param($option['value'], PARAM_INT); break; case 'sortby': $sortallowedvalues = array('id', 'firstname', 'lastname', 'siteorder'); if (!in_array($option['value'], $sortallowedvalues)) { throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $option['value'] . '),' . 'allowed values are: ' . implode(',', $sortallowedvalues)); } if ($option['value'] == 'siteorder') { list($sortby, $sortparams) = users_order_by_sql('us'); } else { $sortby = 'us.' . $option['value']; } break; case 'sortdirection': $sortdirection = strtoupper($option['value']); $directionallowedvalues = array('ASC', 'DESC'); if (!in_array($sortdirection, $directionallowedvalues)) { throw new invalid_parameter_exception('Invalid value for sortdirection parameter (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues)); } break; } } $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); $coursecontext = context_course::instance($courseid, IGNORE_MISSING); if ($courseid == SITEID) { $context = context_system::instance(); } else { $context = $coursecontext; } try { self::validate_context($context); } catch (Exception $e) { $exceptionparam = new stdClass(); $exceptionparam->message = $e->getMessage(); $exceptionparam->courseid = $params['courseid']; throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam); } if ($courseid == SITEID) { require_capability('moodle/site:viewparticipants', $context); } else { require_capability('moodle/course:viewparticipants', $context); } // to overwrite this parameter, you need role:review capability if ($withcapability) { require_capability('moodle/role:review', $coursecontext); } // need accessallgroups capability if you want to overwrite this option if (!empty($groupid) && !groups_is_member($groupid)) { require_capability('moodle/site:accessallgroups', $coursecontext); } // to overwrite this option, you need course:enrolereview permission if ($onlyactive) { require_capability('moodle/course:enrolreview', $coursecontext); } list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive); $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)"; $enrolledparams['contextlevel'] = CONTEXT_USER; $groupjoin = ''; if (empty($groupid) && groups_get_course_groupmode($course) == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $coursecontext)) { // Filter by groups the user can view. $usergroups = groups_get_user_groups($course->id); if (!empty($usergroups['0'])) { list($groupsql, $groupparams) = $DB->get_in_or_equal($usergroups['0'], SQL_PARAMS_NAMED); $groupjoin = "JOIN {groups_members} gm ON (u.id = gm.userid AND gm.groupid {$groupsql})"; $enrolledparams = array_merge($enrolledparams, $groupparams); } else { // User doesn't belong to any group, so he can't see any user. Return an empty array. return array(); } } $sql = "SELECT us.*\n FROM {user} us\n JOIN (\n SELECT DISTINCT u.id {$ctxselect}\n FROM {user} u {$ctxjoin} {$groupjoin}\n WHERE u.id IN ({$enrolledsql})\n ) q ON q.id = us.id\n ORDER BY {$sortby} {$sortdirection}"; $enrolledparams = array_merge($enrolledparams, $sortparams); $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber); $users = array(); foreach ($enrolledusers as $user) { context_helper::preload_from_record($user); if ($userdetails = user_get_user_details($user, $course, $userfields)) { $users[] = $userdetails; } } $enrolledusers->close(); return $users; }
/** * This function gets the list of courses that this user has a particular capability in. * It is still not very efficient. * * @param string $capability Capability in question * @param int $userid User ID or null for current user * @param bool $doanything True if 'doanything' is permitted (default) * @param string $fieldsexceptid Leave blank if you only need 'id' in the course records; * otherwise use a comma-separated list of the fields you require, not including id * @param string $orderby If set, use a comma-separated list of fields from course * table with sql modifiers (DESC) if needed * @return array Array of courses, may have zero entries. Or false if query failed. */ function get_user_capability_course($capability, $userid = null, $doanything = true, $fieldsexceptid = '', $orderby = '') { global $DB; // Convert fields list and ordering $fieldlist = ''; if ($fieldsexceptid) { $fields = explode(',', $fieldsexceptid); foreach($fields as $field) { $fieldlist .= ',c.'.$field; } } if ($orderby) { $fields = explode(',', $orderby); $orderby = ''; foreach($fields as $field) { if ($orderby) { $orderby .= ','; } $orderby .= 'c.'.$field; } $orderby = 'ORDER BY '.$orderby; } // Obtain a list of everything relevant about all courses including context. // Note the result can be used directly as a context (we are going to), the course // fields are just appended. $contextpreload = context_helper::get_preload_record_columns_sql('x'); $courses = array(); $rs = $DB->get_recordset_sql("SELECT c.id $fieldlist, $contextpreload FROM {course} c JOIN {context} x ON (c.id=x.instanceid AND x.contextlevel=".CONTEXT_COURSE.") $orderby"); // Check capability for each course in turn foreach ($rs as $course) { context_helper::preload_from_record($course); $context = context_course::instance($course->id); if (has_capability($capability, $context, $userid, $doanything)) { // We've got the capability. Make the record look like a course record // and store it $courses[] = $course; } } $rs->close(); return empty($courses) ? false : $courses; }
/** * Get all the cohorts defined anywhere in system. * * The function assumes that user capability to view/manage cohorts on system level * has already been verified. This function only checks if such capabilities have been * revoked in child (categories) contexts. * * @param int $page number of the current page * @param int $perpage items per page * @param string $search search string * @return array Array(totalcohorts => int, cohorts => array, allcohorts => int) */ function meditraxcohort_get_all_cohorts($page = 0, $perpage = 25, $search = '') { global $DB; $fields = "SELECT c.*, " . context_helper::get_preload_record_columns_sql('ctx'); $countfields = "SELECT COUNT(*)"; $sql = " FROM {cohort} c\n JOIN {context} ctx ON ctx.id = c.contextid "; $params = array(); $wheresql = ''; if ($excludedcontexts = cohort_get_invisible_contexts()) { list($excludedsql, $excludedparams) = $DB->get_in_or_equal($excludedcontexts, SQL_PARAMS_NAMED, 'excl', false); $wheresql = ' WHERE c.contextid ' . $excludedsql; $params = array_merge($params, $excludedparams); } $totalcohorts = $allcohorts = $DB->count_records_sql($countfields . $sql . $wheresql, $params); if (!empty($search)) { list($searchcondition, $searchparams) = cohort_get_search_query($search, 'c'); $wheresql .= ($wheresql ? ' AND ' : ' WHERE ') . $searchcondition; $params = array_merge($params, $searchparams); $totalcohorts = $DB->count_records_sql($countfields . $sql . $wheresql, $params); } $order = " ORDER BY c.name ASC, c.idnumber ASC"; $cohorts = $DB->get_records_sql($fields . $sql . $wheresql . $order, $params, $page * $perpage, $perpage); // Preload used contexts, they will be used to check view/manage/assign capabilities and display categories names. foreach (array_keys($cohorts) as $key) { context_helper::preload_from_record($cohorts[$key]); } return array('totalcohorts' => $totalcohorts, 'cohorts' => $cohorts, 'allcohorts' => $allcohorts); }
/** * Finds all assignment notifications that have yet to be mailed out, and mails them. * * Cron function to be run periodically according to the moodle cron. * * @return bool */ public static function cron() { global $DB; // Only ever send a max of one days worth of updates. $yesterday = time() - 24 * 3600; $timenow = time(); // Collect all submissions from the past 24 hours that require mailing. $sql = 'SELECT g.id as gradeid, a.course, a.name, a.blindmarking, a.revealidentities, g.*, g.timemodified as lastmodified FROM {assign} a JOIN {assign_grades} g ON g.assignment = a.id LEFT JOIN {assign_user_flags} uf ON uf.assignment = a.id AND uf.userid = g.userid WHERE g.timemodified >= :yesterday AND g.timemodified <= :today AND uf.mailed = 0'; $params = array('yesterday' => $yesterday, 'today' => $timenow); $submissions = $DB->get_records_sql($sql, $params); if (empty($submissions)) { return true; } mtrace('Processing ' . count($submissions) . ' assignment submissions ...'); // Preload courses we are going to need those. $courseids = array(); foreach ($submissions as $submission) { $courseids[] = $submission->course; } // Filter out duplicates. $courseids = array_unique($courseids); $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); list($courseidsql, $params) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED); $sql = 'SELECT c.*, ' . $ctxselect . ' FROM {course} c LEFT JOIN {context} ctx ON ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel WHERE c.id ' . $courseidsql; $params['contextlevel'] = CONTEXT_COURSE; $courses = $DB->get_records_sql($sql, $params); // Clean up... this could go on for a while. unset($courseids); unset($ctxselect); unset($courseidsql); unset($params); // Simple array we'll use for caching modules. $modcache = array(); // Message students about new feedback. foreach ($submissions as $submission) { mtrace("Processing assignment submission {$submission->id} ..."); // Do not cache user lookups - could be too many. if (!($user = $DB->get_record('user', array('id' => $submission->userid)))) { mtrace('Could not find user ' . $submission->userid); continue; } // Use a cache to prevent the same DB queries happening over and over. if (!array_key_exists($submission->course, $courses)) { mtrace('Could not find course ' . $submission->course); continue; } $course = $courses[$submission->course]; if (isset($course->ctxid)) { // Context has not yet been preloaded. Do so now. context_helper::preload_from_record($course); } // Override the language and timezone of the "current" user, so that // mail is customised for the receiver. cron_setup_user($user, $course); // Context lookups are already cached. $coursecontext = context_course::instance($course->id); if (!is_enrolled($coursecontext, $user->id)) { $courseshortname = format_string($course->shortname, true, array('context' => $coursecontext)); mtrace(fullname($user) . ' not an active participant in ' . $courseshortname); continue; } if (!($grader = $DB->get_record('user', array('id' => $submission->grader)))) { mtrace('Could not find grader ' . $submission->grader); continue; } if (!array_key_exists($submission->assignment, $modcache)) { $mod = get_coursemodule_from_instance('assign', $submission->assignment, $course->id); if (empty($mod)) { mtrace('Could not find course module for assignment id ' . $submission->assignment); continue; } $modcache[$submission->assignment] = $mod; } else { $mod = $modcache[$submission->assignment]; } // Context lookups are already cached. $contextmodule = context_module::instance($mod->id); if (!$mod->visible) { // Hold mail notification for hidden assignments until later. continue; } // Need to send this to the student. $messagetype = 'feedbackavailable'; $eventtype = 'assign_notification'; $updatetime = $submission->lastmodified; $modulename = get_string('modulename', 'assign'); $uniqueid = 0; if ($submission->blindmarking && !$submission->revealidentities) { $uniqueid = self::get_uniqueid_for_user_static($submission->assignment, $user->id); } $showusers = $submission->blindmarking && !$submission->revealidentities; self::send_assignment_notification($grader, $user, $messagetype, $eventtype, $updatetime, $mod, $contextmodule, $course, $modulename, $submission->name, $showusers, $uniqueid); $flags = $DB->get_record('assign_user_flags', array('userid' => $user->id, 'assignment' => $submission->assignment)); if ($flags) { $flags->mailed = 1; $DB->update_record('assign_user_flags', $flags); } else { $flags = new stdClass(); $flags->userid = $user->id; $flags->assignment = $submission->assignment; $flags->mailed = 1; $DB->insert_record('assign_user_flags', $flags); } mtrace('Done'); } mtrace('Done processing ' . count($submissions) . ' assignment submissions'); cron_setup_user(); // Free up memory just to be sure. unset($courses); unset($modcache); return true; }
/** * A small functional test of accesslib functions and classes. * @return void */ public function test_everything_in_accesslib() { global $USER, $SITE, $CFG, $DB, $ACCESSLIB_PRIVATE; $this->resetAfterTest(true); $generator = $this->getDataGenerator(); // Fill the site with some real data $testcategories = array(); $testcourses = array(); $testpages = array(); $testblocks = array(); $allroles = $DB->get_records_menu('role', array(), 'id', 'archetype, id'); $systemcontext = context_system::instance(); $frontpagecontext = context_course::instance(SITEID); // Add block to system context $bi = $generator->create_block('online_users'); context_block::instance($bi->id); $testblocks[] = $bi->id; // Some users $testusers = array(); for($i=0; $i<20; $i++) { $user = $generator->create_user(); $testusers[$i] = $user->id; $usercontext = context_user::instance($user->id); // Add block to user profile $bi = $generator->create_block('online_users', array('parentcontextid'=>$usercontext->id)); $testblocks[] = $bi->id; } // Deleted user - should be ignored everywhere, can not have context $generator->create_user(array('deleted'=>1)); // Add block to frontpage $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagecontext->id)); $frontpageblockcontext = context_block::instance($bi->id); $testblocks[] = $bi->id; // Add a resource to frontpage $page = $generator->create_module('page', array('course'=>$SITE->id)); $testpages[] = $page->id; $frontpagepagecontext = context_module::instance($page->cmid); // Add block to frontpage resource $bi = $generator->create_block('online_users', array('parentcontextid'=>$frontpagepagecontext->id)); $frontpagepageblockcontext = context_block::instance($bi->id); $testblocks[] = $bi->id; // Some nested course categories with courses $manualenrol = enrol_get_plugin('manual'); $parentcat = 0; for($i=0; $i<5; $i++) { $cat = $generator->create_category(array('parent'=>$parentcat)); $testcategories[] = $cat->id; $catcontext = context_coursecat::instance($cat->id); $parentcat = $cat->id; if ($i >=4) { continue; } // Add resource to each category $bi = $generator->create_block('online_users', array('parentcontextid'=>$catcontext->id)); context_block::instance($bi->id); // Add a few courses to each category for($j=0; $j<6; $j++) { $course = $generator->create_course(array('category'=>$cat->id)); $testcourses[] = $course->id; $coursecontext = context_course::instance($course->id); if ($j >= 5) { continue; } // Add manual enrol instance $manualenrol->add_default_instance($DB->get_record('course', array('id'=>$course->id))); // Add block to each course $bi = $generator->create_block('online_users', array('parentcontextid'=>$coursecontext->id)); $testblocks[] = $bi->id; // Add a resource to each course $page = $generator->create_module('page', array('course'=>$course->id)); $testpages[] = $page->id; $modcontext = context_module::instance($page->cmid); // Add block to each module $bi = $generator->create_block('online_users', array('parentcontextid'=>$modcontext->id)); $testblocks[] = $bi->id; } } // Make sure all contexts were created properly $count = 1; //system $count += $DB->count_records('user', array('deleted'=>0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEquals($DB->count_records('context'), $count); $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0); $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0); // ====== context_helper::get_level_name() ================================ $levels = context_helper::get_all_levels(); foreach ($levels as $level=>$classname) { $name = context_helper::get_level_name($level); $this->assertFalse(empty($name)); } // ======= context::instance_by_id(), context_xxx::instance(); $context = context::instance_by_id($frontpagecontext->id); $this->assertSame($context->contextlevel, CONTEXT_COURSE); $this->assertFalse(context::instance_by_id(-1, IGNORE_MISSING)); try { context::instance_by_id(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $this->assertTrue(context_system::instance() instanceof context_system); $this->assertTrue(context_coursecat::instance($testcategories[0]) instanceof context_coursecat); $this->assertTrue(context_course::instance($testcourses[0]) instanceof context_course); $this->assertTrue(context_module::instance($testpages[0]) instanceof context_module); $this->assertTrue(context_block::instance($testblocks[0]) instanceof context_block); $this->assertFalse(context_coursecat::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_course::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_module::instance(-1, IGNORE_MISSING)); $this->assertFalse(context_block::instance(-1, IGNORE_MISSING)); try { context_coursecat::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_course::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_module::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } try { context_block::instance(-1); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } // ======= $context->get_url(), $context->get_context_name(), $context->get_capabilities() ========= $testcontexts = array(); $testcontexts[CONTEXT_SYSTEM] = context_system::instance(); $testcontexts[CONTEXT_COURSECAT] = context_coursecat::instance($testcategories[0]); $testcontexts[CONTEXT_COURSE] = context_course::instance($testcourses[0]); $testcontexts[CONTEXT_MODULE] = context_module::instance($testpages[0]); $testcontexts[CONTEXT_BLOCK] = context_block::instance($testblocks[0]); foreach ($testcontexts as $context) { $name = $context->get_context_name(true, true); $this->assertFalse(empty($name)); $this->assertTrue($context->get_url() instanceof moodle_url); $caps = $context->get_capabilities(); $this->assertTrue(is_array($caps)); foreach ($caps as $cap) { $cap = (array)$cap; $this->assertSame(array_keys($cap), array('id', 'name', 'captype', 'contextlevel', 'component', 'riskbitmask')); } } unset($testcontexts); // ===== $context->get_course_context() ========================================= $this->assertFalse($systemcontext->get_course_context(false)); try { $systemcontext->get_course_context(); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $context = context_coursecat::instance($testcategories[0]); $this->assertFalse($context->get_course_context(false)); try { $context->get_course_context(); $this->fail('exception expected'); } catch (Exception $e) { $this->assertTrue(true); } $this->assertSame($frontpagecontext->get_course_context(true), $frontpagecontext); $this->assertSame($frontpagepagecontext->get_course_context(true), $frontpagecontext); $this->assertSame($frontpagepageblockcontext->get_course_context(true), $frontpagecontext); // ======= $context->get_parent_context(), $context->get_parent_contexts(), $context->get_parent_context_ids() ======= $userid = reset($testusers); $usercontext = context_user::instance($userid); $this->assertSame($usercontext->get_parent_context(), $systemcontext); $this->assertSame($usercontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext)); $this->assertSame($usercontext->get_parent_contexts(true), array($usercontext->id=>$usercontext, $systemcontext->id=>$systemcontext)); $this->assertSame($systemcontext->get_parent_contexts(), array()); $this->assertSame($systemcontext->get_parent_contexts(true), array($systemcontext->id=>$systemcontext)); $this->assertSame($systemcontext->get_parent_context_ids(), array()); $this->assertSame($systemcontext->get_parent_context_ids(true), array($systemcontext->id)); $this->assertSame($frontpagecontext->get_parent_context(), $systemcontext); $this->assertSame($frontpagecontext->get_parent_contexts(), array($systemcontext->id=>$systemcontext)); $this->assertSame($frontpagecontext->get_parent_contexts(true), array($frontpagecontext->id=>$frontpagecontext, $systemcontext->id=>$systemcontext)); $this->assertSame($frontpagecontext->get_parent_context_ids(), array($systemcontext->id)); $this->assertEquals($frontpagecontext->get_parent_context_ids(true), array($frontpagecontext->id, $systemcontext->id)); $this->assertSame($systemcontext->get_parent_context(), false); $frontpagecontext = context_course::instance($SITE->id); $parent = $systemcontext; foreach ($testcategories as $catid) { $catcontext = context_coursecat::instance($catid); $this->assertSame($catcontext->get_parent_context(), $parent); $parent = $catcontext; } $this->assertSame($frontpagepagecontext->get_parent_context(), $frontpagecontext); $this->assertSame($frontpageblockcontext->get_parent_context(), $frontpagecontext); $this->assertSame($frontpagepageblockcontext->get_parent_context(), $frontpagepagecontext); // ====== $context->get_child_contexts() ================================ $CFG->debug = 0; $children = $systemcontext->get_child_contexts(); $CFG->debug = DEBUG_DEVELOPER; $this->assertEquals(count($children)+1, $DB->count_records('context')); $context = context_coursecat::instance($testcategories[3]); $children = $context->get_child_contexts(); $countcats = 0; $countcourses = 0; $countblocks = 0; foreach ($children as $child) { if ($child->contextlevel == CONTEXT_COURSECAT) { $countcats++; } if ($child->contextlevel == CONTEXT_COURSE) { $countcourses++; } if ($child->contextlevel == CONTEXT_BLOCK) { $countblocks++; } } $this->assertEquals(count($children), 8); $this->assertEquals($countcats, 1); $this->assertEquals($countcourses, 6); $this->assertEquals($countblocks, 1); $context = context_course::instance($testcourses[2]); $children = $context->get_child_contexts(); $this->assertEquals(count($children), 7); // depends on number of default blocks $context = context_module::instance($testpages[3]); $children = $context->get_child_contexts(); $this->assertEquals(count($children), 1); $context = context_block::instance($testblocks[1]); $children = $context->get_child_contexts(); $this->assertEquals(count($children), 0); unset($children); unset($countcats); unset($countcourses); unset($countblocks); // ======= context_helper::reset_caches() ============================ context_helper::reset_caches(); $this->assertEquals(context_inspection::test_context_cache_size(), 0); context_course::instance($SITE->id); $this->assertEquals(context_inspection::test_context_cache_size(), 1); // ======= context preloading ======================================== context_helper::reset_caches(); $sql = "SELECT ".context_helper::get_preload_record_columns_sql('c')." FROM {context} c WHERE c.contextlevel <> ".CONTEXT_SYSTEM; $records = $DB->get_records_sql($sql); $firstrecord = reset($records); $columns = context_helper::get_preload_record_columns('c'); $firstrecord = (array)$firstrecord; $this->assertSame(array_keys($firstrecord), array_values($columns)); context_helper::reset_caches(); foreach ($records as $record) { context_helper::preload_from_record($record); $this->assertEquals($record, new stdClass()); } $this->assertEquals(context_inspection::test_context_cache_size(), count($records)); unset($records); unset($columns); context_helper::reset_caches(); context_helper::preload_course($SITE->id); $this->assertEquals(7, context_inspection::test_context_cache_size()); // depends on number of default blocks // ====== assign_capability(), unassign_capability() ==================== $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertFalse($rc); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext->id); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertEquals($rc->permission, CAP_ALLOW); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext->id); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertEquals($rc->permission, CAP_ALLOW); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $allroles['teacher'], $frontpagecontext, true); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertEquals($rc->permission, CAP_PREVENT); assign_capability('moodle/site:accessallgroups', CAP_INHERIT, $allroles['teacher'], $frontpagecontext); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertFalse($rc); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $allroles['teacher'], $frontpagecontext); unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext, true); $rc = $DB->get_record('role_capabilities', array('contextid'=>$frontpagecontext->id, 'roleid'=>$allroles['teacher'], 'capability'=>'moodle/site:accessallgroups')); $this->assertFalse($rc); unassign_capability('moodle/site:accessallgroups', $allroles['teacher'], $frontpagecontext->id, true); unset($rc); accesslib_clear_all_caches(false); // must be done after assign_capability() // ======= role_assign(), role_unassign(), role_unassign_all() ============== $context = context_course::instance($testcourses[1]); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0); role_assign($allroles['teacher'], $testusers[1], $context->id); role_assign($allroles['teacher'], $testusers[2], $context->id); role_assign($allroles['manager'], $testusers[1], $context->id); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 3); role_unassign($allroles['teacher'], $testusers[1], $context->id); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 2); role_unassign_all(array('contextid'=>$context->id)); $this->assertEquals($DB->count_records('role_assignments', array('contextid'=>$context->id)), 0); unset($context); accesslib_clear_all_caches(false); // just in case // ====== has_capability(), get_users_by_capability(), role_switch(), reload_all_capabilities() and friends ======================== $adminid = get_admin()->id; $guestid = $CFG->siteguest; // Enrol some users into some courses $course1 = $DB->get_record('course', array('id'=>$testcourses[22]), '*', MUST_EXIST); $course2 = $DB->get_record('course', array('id'=>$testcourses[7]), '*', MUST_EXIST); $cms = $DB->get_records('course_modules', array('course'=>$course1->id), 'id'); $cm1 = reset($cms); $blocks = $DB->get_records('block_instances', array('parentcontextid'=>context_module::instance($cm1->id)->id), 'id'); $block1 = reset($blocks); $instance1 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course1->id)); $instance2 = $DB->get_record('enrol', array('enrol'=>'manual', 'courseid'=>$course2->id)); for($i=0; $i<9; $i++) { $manualenrol->enrol_user($instance1, $testusers[$i], $allroles['student']); } $manualenrol->enrol_user($instance1, $testusers[8], $allroles['teacher']); $manualenrol->enrol_user($instance1, $testusers[9], $allroles['editingteacher']); for($i=10; $i<15; $i++) { $manualenrol->enrol_user($instance2, $testusers[$i], $allroles['student']); } $manualenrol->enrol_user($instance2, $testusers[15], $allroles['editingteacher']); // Add tons of role assignments - the more the better role_assign($allroles['coursecreator'], $testusers[11], context_coursecat::instance($testcategories[2])); role_assign($allroles['manager'], $testusers[12], context_coursecat::instance($testcategories[1])); role_assign($allroles['student'], $testusers[9], context_module::instance($cm1->id)); role_assign($allroles['teacher'], $testusers[8], context_module::instance($cm1->id)); role_assign($allroles['guest'], $testusers[13], context_course::instance($course1->id)); role_assign($allroles['teacher'], $testusers[7], context_block::instance($block1->id)); role_assign($allroles['manager'], $testusers[9], context_block::instance($block1->id)); role_assign($allroles['editingteacher'], $testusers[9], context_course::instance($course1->id)); role_assign($allroles['teacher'], $adminid, context_course::instance($course1->id)); role_assign($allroles['editingteacher'], $adminid, context_block::instance($block1->id)); // Add tons of overrides - the more the better assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpageblockcontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpageblockcontext, true); assign_capability('moodle/block:view', CAP_PROHIBIT, $allroles['guest'], $frontpageblockcontext, true); assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['user'], $frontpageblockcontext, true); assign_capability('block/online_users:viewlist', CAP_PREVENT, $allroles['student'], $frontpageblockcontext, true); assign_capability('moodle/site:accessallgroups', CAP_PREVENT, $CFG->defaultuserroleid, $frontpagepagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagepagecontext, true); assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $frontpagepagecontext, true); assign_capability('mod/page:view', CAP_ALLOW, $allroles['user'], $frontpagepagecontext, true); assign_capability('moodle/page:view', CAP_ALLOW, $allroles['student'], $frontpagepagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultuserroleid, $frontpagecontext, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $CFG->defaultfrontpageroleid, $frontpagecontext, true); assign_capability('mod/page:view', CAP_ALLOW, $allroles['guest'], $frontpagecontext, true); assign_capability('mod/page:view', CAP_PROHIBIT, $allroles['user'], $frontpagecontext, true); assign_capability('mod/page:view', CAP_PREVENT, $allroles['guest'], $systemcontext, true); accesslib_clear_all_caches(false); // must be done after assign_capability() // Extra tests for guests and not-logged-in users because they can not be verified by cross checking // with get_users_by_capability() where they are ignored $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, $guestid)); $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, $guestid)); $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, $guestid)); $this->assertFalse(has_capability('mod/page:view', $systemcontext, $guestid)); $this->assertFalse(has_capability('moodle/block:view', $frontpageblockcontext, 0)); $this->assertFalse(has_capability('mod/page:view', $frontpagepagecontext, 0)); $this->assertTrue(has_capability('mod/page:view', $frontpagecontext, 0)); $this->assertFalse(has_capability('mod/page:view', $systemcontext, 0)); $this->assertFalse(has_capability('moodle/course:create', $systemcontext, $testusers[11])); $this->assertTrue(has_capability('moodle/course:create', context_coursecat::instance($testcategories[2]), $testusers[11])); $this->assertFalse(has_capability('moodle/course:create', context_course::instance($testcourses[1]), $testusers[11])); $this->assertTrue(has_capability('moodle/course:create', context_course::instance($testcourses[19]), $testusers[11])); $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[1]), $testusers[9])); $this->assertFalse(has_capability('moodle/course:update', context_course::instance($testcourses[19]), $testusers[9])); $this->assertFalse(has_capability('moodle/course:update', $systemcontext, $testusers[9])); // Test the list of enrolled users $coursecontext = context_course::instance($course1->id); $enrolled = get_enrolled_users($coursecontext); $this->assertEquals(count($enrolled), 10); for($i=0; $i<10; $i++) { $this->assertTrue(isset($enrolled[$testusers[$i]])); } $enrolled = get_enrolled_users($coursecontext, 'moodle/course:update'); $this->assertEquals(count($enrolled), 1); $this->assertTrue(isset($enrolled[$testusers[9]])); unset($enrolled); // role switching $userid = $testusers[9]; $USER = $DB->get_record('user', array('id'=>$userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); $this->assertFalse(is_role_switched($course1->id)); role_switch($allroles['student'], $coursecontext); $this->assertTrue(is_role_switched($course1->id)); $this->assertEquals($USER->access['rsw'][$coursecontext->path], $allroles['student']); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); role_switch(0, $coursecontext); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); $userid = $adminid; $USER = $DB->get_record('user', array('id'=>$userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $blockcontext = context_block::instance($block1->id); $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); role_switch($allroles['student'], $coursecontext); $this->assertEquals($USER->access['rsw'][$coursecontext->path], $allroles['student']); $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $blockcontext)); load_all_capabilities(); $this->assertTrue(has_capability('moodle/course:update', $blockcontext)); // temp course role for enrol $DB->delete_records('cache_flags', array()); // this prevents problem with dirty contexts immediately resetting the temp role - this is a known problem... $userid = $testusers[5]; $roleid = $allroles['editingteacher']; $USER = $DB->get_record('user', array('id'=>$userid)); load_all_capabilities(); $coursecontext = context_course::instance($course1->id); $this->assertFalse(has_capability('moodle/course:update', $coursecontext)); $this->assertFalse(isset($USER->access['ra'][$coursecontext->path][$roleid])); load_temp_course_role($coursecontext, $roleid); $this->assertEquals($USER->access['ra'][$coursecontext->path][$roleid], $roleid); $this->assertTrue(has_capability('moodle/course:update', $coursecontext)); remove_temp_course_roles($coursecontext); $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); load_temp_course_role($coursecontext, $roleid); reload_all_capabilities(); $this->assertFalse(has_capability('moodle/course:update', $coursecontext, $userid)); $USER = new stdClass(); $USER->id = 0; // Now cross check has_capability() with get_users_by_capability(), each using different code paths, // they have to be kept in sync, usually only one of them breaks, so we know when something is wrong, // at the same time validate extra restrictions (guest read only no risks, admin exception, non existent and deleted users) $contexts = $DB->get_records('context', array(), 'id'); $contexts = array_values($contexts); $capabilities = $DB->get_records('capabilities', array(), 'id'); $capabilities = array_values($capabilities); $roles = array($allroles['guest'], $allroles['user'], $allroles['teacher'], $allroles['editingteacher'], $allroles['coursecreator'], $allroles['manager']); $userids = array_values($testusers); $userids[] = get_admin()->id; if (!PHPUNIT_LONGTEST) { $contexts = array_slice($contexts, 0, 10); $capabilities = array_slice($capabilities, 0, 5); $userids = array_slice($userids, 0, 5); } // Random time! //srand(666); foreach($userids as $userid) { // no guest or deleted // each user gets 0-10 random roles $rcount = rand(0, 10); for($j=0; $j<$rcount; $j++) { $roleid = $roles[rand(0, count($roles)-1)]; $contextid = $contexts[rand(0, count($contexts)-1)]->id; role_assign($roleid, $userid, $contextid); } } $permissions = array(CAP_ALLOW, CAP_PREVENT, CAP_INHERIT, CAP_PREVENT); $maxoverrides = count($contexts)*10; for($j=0; $j<$maxoverrides; $j++) { $roleid = $roles[rand(0, count($roles)-1)]; $contextid = $contexts[rand(0, count($contexts)-1)]->id; $permission = $permissions[rand(0,count($permissions)-1)]; $capname = $capabilities[rand(0, count($capabilities)-1)]->name; assign_capability($capname, $permission, $roleid, $contextid, true); } unset($permissions); unset($roles); accesslib_clear_all_caches(false); // must be done after assign_capability() // Test time - let's set up some real user, just in case the logic for USER affects the others... $USER = $DB->get_record('user', array('id'=>$testusers[3])); load_all_capabilities(); $userids[] = $CFG->siteguest; $userids[] = 0; // not-logged-in user $userids[] = -1; // non-existent user foreach ($contexts as $crecord) { $context = context::instance_by_id($crecord->id); if ($coursecontext = $context->get_course_context(false)) { $enrolled = get_enrolled_users($context); } else { $enrolled = array(); } foreach ($capabilities as $cap) { $allowed = get_users_by_capability($context, $cap->name, 'u.id, u.username'); if ($enrolled) { $enrolledwithcap = get_enrolled_users($context, $cap->name); } else { $enrolledwithcap = array(); } foreach ($userids as $userid) { if ($userid == 0 or isguestuser($userid)) { if ($userid == 0) { $CFG->forcelogin = true; $this->assertFalse(has_capability($cap->name, $context, $userid)); unset($CFG->forcelogin); } if (($cap->captype === 'write') or ($cap->riskbitmask & (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))) { $this->assertFalse(has_capability($cap->name, $context, $userid)); } $this->assertFalse(isset($allowed[$userid])); } else { if (is_siteadmin($userid)) { $this->assertTrue(has_capability($cap->name, $context, $userid, true)); } $hascap = has_capability($cap->name, $context, $userid, false); $this->assertSame($hascap, isset($allowed[$userid]), "Capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." "); if (isset($enrolled[$userid])) { $this->assertSame(isset($allowed[$userid]), isset($enrolledwithcap[$userid]), "Enrolment with capability result mismatch user:$userid, context:$context->id, $cap->name, hascap: ".(int)$hascap." "); } } } } } // Back to nobody $USER = new stdClass(); $USER->id = 0; unset($contexts); unset($userids); unset($capabilities); // Now let's do all the remaining tests that break our carefully prepared fake site // ======= $context->mark_dirty() ======================================= $DB->delete_records('cache_flags', array()); accesslib_clear_all_caches(false); $systemcontext->mark_dirty(); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$systemcontext->path])); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$systemcontext->path])); // ======= $context->reload_if_dirty(); ================================= $DB->delete_records('cache_flags', array()); accesslib_clear_all_caches(false); load_all_capabilities(); $context = context_course::instance($testcourses[2]); $page = $DB->get_record('page', array('course'=>$testcourses[2])); $pagecontext = context_module::instance($page->id); $context->mark_dirty(); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); $USER->access['test'] = true; $context->reload_if_dirty(); $this->assertFalse(isset($USER->access['test'])); $context->mark_dirty(); $this->assertTrue(isset($ACCESSLIB_PRIVATE->dirtycontexts[$context->path])); $USER->access['test'] = true; $pagecontext->reload_if_dirty(); $this->assertFalse(isset($USER->access['test'])); // ======= context_helper::build_all_paths() ============================ $oldcontexts = $DB->get_records('context', array(), 'id'); $DB->set_field_select('context', 'path', NULL, "contextlevel <> ".CONTEXT_SYSTEM); $DB->set_field_select('context', 'depth', 0, "contextlevel <> ".CONTEXT_SYSTEM); context_helper::build_all_paths(); $newcontexts = $DB->get_records('context', array(), 'id'); $this->assertEquals($oldcontexts, $newcontexts); unset($oldcontexts); unset($newcontexts); // ======= $context->reset_paths() ====================================== $context = context_course::instance($testcourses[2]); $children = $context->get_child_contexts(); $context->reset_paths(false); $this->assertSame($DB->get_field('context', 'path', array('id'=>$context->id)), NULL); $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), 0); foreach ($children as $child) { $this->assertSame($DB->get_field('context', 'path', array('id'=>$child->id)), NULL); $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$child->id)), 0); } $this->assertEquals(count($children)+1, $DB->count_records('context', array('depth'=>0))); $this->assertEquals(count($children)+1, $DB->count_records('context', array('path'=>NULL))); $context = context_course::instance($testcourses[2]); $context->reset_paths(true); $context = context_course::instance($testcourses[2]); $this->assertEquals($DB->get_field('context', 'path', array('id'=>$context->id)), $context->path); $this->assertEquals($DB->get_field('context', 'depth', array('id'=>$context->id)), $context->depth); $this->assertEquals(0, $DB->count_records('context', array('depth'=>0))); $this->assertEquals(0, $DB->count_records('context', array('path'=>NULL))); // ====== $context->update_moved(); ====================================== accesslib_clear_all_caches(false); $DB->delete_records('cache_flags', array()); $course = $DB->get_record('course', array('id'=>$testcourses[0])); $context = context_course::instance($course->id); $oldpath = $context->path; $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); $categorycontext = context_coursecat::instance($miscid); $course->category = $miscid; $DB->update_record('course', $course); $context->update_moved($categorycontext); $context = context_course::instance($course->id); $this->assertEquals($context->get_parent_context(), $categorycontext); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$oldpath])); $this->assertTrue(isset($dirty[$context->path])); // ====== $context->delete_content() ===================================== context_helper::reset_caches(); $context = context_module::instance($testpages[3]); $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); $context->delete_content(); $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); // ====== $context->delete() ============================= context_helper::reset_caches(); $context = context_module::instance($testpages[4]); $this->assertTrue($DB->record_exists('context', array('id'=>$context->id))); $this->assertEquals(1, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); $bi = $DB->get_record('block_instances', array('parentcontextid'=>$context->id)); $bicontext = context_block::instance($bi->id); $DB->delete_records('cache_flags', array()); $context->delete(); // should delete also linked blocks $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$context->path])); $this->assertFalse($DB->record_exists('context', array('id'=>$context->id))); $this->assertFalse($DB->record_exists('context', array('id'=>$bicontext->id))); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_MODULE, 'instanceid'=>$testpages[4]))); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK, 'instanceid'=>$bi->id))); $this->assertEquals(0, $DB->count_records('block_instances', array('parentcontextid'=>$context->id))); context_module::instance($testpages[4]); // ====== context_helper::delete_instance() ============================= context_helper::reset_caches(); $lastcourse = array_pop($testcourses); $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse))); $coursecontext = context_course::instance($lastcourse); $this->assertEquals(context_inspection::test_context_cache_size(), 1); $this->assertFalse($coursecontext->instanceid == CONTEXT_COURSE); $DB->delete_records('cache_flags', array()); context_helper::delete_instance(CONTEXT_COURSE, $lastcourse); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$coursecontext->path])); $this->assertEquals(context_inspection::test_context_cache_size(), 0); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$lastcourse))); context_course::instance($lastcourse); // ======= context_helper::create_instances() ========================== $prevcount = $DB->count_records('context'); $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); context_helper::create_instances(null, true); $this->assertSame($DB->count_records('context'), $prevcount); $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0); $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0); $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); $DB->delete_records('block_instances', array()); $prevcount = $DB->count_records('context'); $DB->delete_records_select('context', 'contextlevel <> '.CONTEXT_SYSTEM); context_helper::create_instances(null, true); $this->assertSame($DB->count_records('context'), $prevcount); $this->assertEquals($DB->count_records('context', array('depth'=>0)), 0); $this->assertEquals($DB->count_records('context', array('path'=>NULL)), 0); // ======= context_helper::cleanup_instances() ========================== $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}"); $DB->delete_records('course', array('id'=>$lastcourse)); $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}"); $DB->delete_records('course_categories', array('id'=>$lastcategory)); $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0"); $DB->delete_records('user', array('id'=>$lastuser)); $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id)); $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid)); context_helper::cleanup_instances(); $count = 1; //system $count += $DB->count_records('user', array('deleted'=>0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEquals($DB->count_records('context'), $count); // ======= context cache size restrictions ============================== $testusers= array(); for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) { $user = $generator->create_user(); $testusers[$i] = $user->id; } context_helper::create_instances(null, true); context_helper::reset_caches(); for ($i=0; $i<CONTEXT_CACHE_MAX_SIZE + 100; $i++) { context_user::instance($testusers[$i]); if ($i == CONTEXT_CACHE_MAX_SIZE - 1) { $this->assertEquals(context_inspection::test_context_cache_size(), CONTEXT_CACHE_MAX_SIZE); } else if ($i == CONTEXT_CACHE_MAX_SIZE) { // once the limit is reached roughly 1/3 of records should be removed from cache $this->assertEquals(context_inspection::test_context_cache_size(), (int)(CONTEXT_CACHE_MAX_SIZE * (2/3) +102)); } } // We keep the first 100 cached $prevsize = context_inspection::test_context_cache_size(); for ($i=0; $i<100; $i++) { context_user::instance($testusers[$i]); $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize); } context_user::instance($testusers[102]); $this->assertEquals(context_inspection::test_context_cache_size(), $prevsize+1); unset($testusers); // ================================================================= // ======= basic test of legacy functions ========================== // ================================================================= // note: watch out, the fake site might be pretty borked already $this->assertSame(get_system_context(), context_system::instance()); foreach ($DB->get_records('context') as $contextid=>$record) { $context = context::instance_by_id($contextid); $this->assertSame(get_context_instance_by_id($contextid), $context); $this->assertSame(get_context_instance($record->contextlevel, $record->instanceid), $context); $this->assertSame(get_parent_contexts($context), $context->get_parent_context_ids()); if ($context->id == SYSCONTEXTID) { $this->assertSame(get_parent_contextid($context), false); } else { $this->assertSame(get_parent_contextid($context), $context->get_parent_context()->id); } } $CFG->debug = 0; $children = get_child_contexts($systemcontext); $CFG->debug = DEBUG_DEVELOPER; $this->assertEquals(count($children), $DB->count_records('context')-1); unset($children); $DB->delete_records('context', array('contextlevel'=>CONTEXT_BLOCK)); create_contexts(); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_BLOCK))); $DB->set_field('context', 'depth', 0, array('contextlevel'=>CONTEXT_BLOCK)); build_context_path(); $this->assertFalse($DB->record_exists('context', array('depth'=>0))); $lastcourse = $DB->get_field_sql("SELECT MAX(id) FROM {course}"); $DB->delete_records('course', array('id'=>$lastcourse)); $lastcategory = $DB->get_field_sql("SELECT MAX(id) FROM {course_categories}"); $DB->delete_records('course_categories', array('id'=>$lastcategory)); $lastuser = $DB->get_field_sql("SELECT MAX(id) FROM {user} WHERE deleted=0"); $DB->delete_records('user', array('id'=>$lastuser)); $DB->delete_records('block_instances', array('parentcontextid'=>$frontpagepagecontext->id)); $DB->delete_records('course_modules', array('id'=>$frontpagepagecontext->instanceid)); cleanup_contexts(); $count = 1; //system $count += $DB->count_records('user', array('deleted'=>0)); $count += $DB->count_records('course_categories'); $count += $DB->count_records('course'); $count += $DB->count_records('course_modules'); $count += $DB->count_records('block_instances'); $this->assertEquals($DB->count_records('context'), $count); context_helper::reset_caches(); preload_course_contexts($SITE->id); $this->assertEquals(context_inspection::test_context_cache_size(), 1); context_helper::reset_caches(); list($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx'); $sql = "SELECT c.id $select FROM {course_categories} c $join"; $records = $DB->get_records_sql($sql); foreach ($records as $record) { context_instance_preload($record); $record = (array)$record; $this->assertEquals(1, count($record)); // only id left } $this->assertEquals(count($records), context_inspection::test_context_cache_size()); accesslib_clear_all_caches(true); $DB->delete_records('cache_flags', array()); mark_context_dirty($systemcontext->path); $dirty = get_cache_flags('accesslib/dirtycontexts', time()-2); $this->assertTrue(isset($dirty[$systemcontext->path])); accesslib_clear_all_caches(false); $DB->delete_records('cache_flags', array()); $course = $DB->get_record('course', array('id'=>$testcourses[2])); $context = get_context_instance(CONTEXT_COURSE, $course->id); $oldpath = $context->path; $miscid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}"); $categorycontext = context_coursecat::instance($miscid); $course->category = $miscid; $DB->update_record('course', $course); context_moved($context, $categorycontext); $context = get_context_instance(CONTEXT_COURSE, $course->id); $this->assertEquals($context->get_parent_context(), $categorycontext); $this->assertTrue($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2]))); delete_context(CONTEXT_COURSE, $testcourses[2]); $this->assertFalse($DB->record_exists('context', array('contextlevel'=>CONTEXT_COURSE, 'instanceid'=>$testcourses[2]))); $name = get_contextlevel_name(CONTEXT_COURSE); $this->assertFalse(empty($name)); $context = get_context_instance(CONTEXT_COURSE, $testcourses[2]); $name = print_context_name($context); $this->assertFalse(empty($name)); $url = get_context_url($coursecontext); $this->assertFalse($url instanceof modole_url); $page = $DB->get_record('page', array('id'=>$testpages[7])); $context = get_context_instance(CONTEXT_MODULE, $page->id); $coursecontext = get_course_context($context); $this->assertEquals($coursecontext->contextlevel, CONTEXT_COURSE); $this->assertEquals(get_courseid_from_context($context), $page->course); $caps = fetch_context_capabilities($systemcontext); $this->assertTrue(is_array($caps)); unset($caps); }
if ($accesssince) { $wheres[] = get_user_lastaccess_sql($accesssince); } } else { $select = "SELECT {$mainuserfields}, COALESCE(ul.timeaccess, 0) AS lastaccess{$extrasql}"; $joins[] = "JOIN ({$esql}) e ON e.id = u.id"; // Course enrolled users only. $joins[] = "LEFT JOIN {user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = :courseid)"; // Not everybody accessed course yet. $params['courseid'] = $course->id; if ($accesssince) { $wheres[] = get_course_lastaccess_sql($accesssince); } } // Performance hacks - we preload user contexts together with accounts. $ccselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)"; $params['contextlevel'] = CONTEXT_USER; $select .= $ccselect; $joins[] = $ccjoin; // Limit list to users with some role only. if ($roleid) { // We want to query both the current context and parent contexts. list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'relatedctx'); $wheres[] = "u.id IN (SELECT userid FROM {role_assignments} WHERE roleid = :roleid AND contextid {$relatedctxsql})"; $params = array_merge($params, array('roleid' => $roleid), $relatedctxparams); } $from = implode("\n", $joins); if ($wheres) { $where = "WHERE " . implode(" AND ", $wheres); } else {
/** * Preloads context information together with instances. * Use context_instance_preload() to strip the context info from the record and cache the context instance. * * If you are using this methid, you should have something like this: * * list($ctxselect, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); * * To prevent the use of this deprecated function, replace the line above with something similar to this: * * $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); * ^ * $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; * ^ ^ ^ ^ * $params = array('contextlevel' => CONTEXT_COURSE); * ^ * @see context_helper:;get_preload_record_columns_sql() * @deprecated since 2.2 * @param string $joinon for example 'u.id' * @param string $contextlevel context level of instance in $joinon * @param string $tablealias context table alias * @return array with two values - select and join part */ function context_instance_preload_sql($joinon, $contextlevel, $tablealias) { debugging('context_instance_preload_sql() is deprecated, please use context_helper::get_preload_record_columns_sql() instead.', DEBUG_DEVELOPER); $select = ", " . context_helper::get_preload_record_columns_sql($tablealias); $join = "LEFT JOIN {context} {$tablealias} ON ({$tablealias}.instanceid = {$joinon} AND {$tablealias}.contextlevel = {$contextlevel})"; return array($select, $join); }
/** * This function gets called by {@link settings_navigation::load_user_settings()} and actually works out * what can be shown/done * * @param int $courseid The current course' id * @param int $userid The user id to load for * @param string $gstitle The string to pass to get_string for the branch title * @return navigation_node|false */ protected function generate_user_settings($courseid, $userid, $gstitle = 'usercurrentsettings') { global $DB, $CFG, $USER, $SITE; if ($courseid != $SITE->id) { if (!empty($this->page->course->id) && $this->page->course->id == $courseid) { $course = $this->page->course; } else { $select = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT c.*, {$select}\n FROM {course} c\n JOIN {context} ctx ON c.id = ctx.instanceid\n WHERE c.id = :courseid AND ctx.contextlevel = :contextlevel"; $params = array('courseid' => $courseid, 'contextlevel' => CONTEXT_COURSE); $course = $DB->get_record_sql($sql, $params, MUST_EXIST); context_helper::preload_from_record($course); } } else { $course = $SITE; } $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id); // Course context $systemcontext = get_system_context(); $currentuser = $USER->id == $userid; if ($currentuser) { $user = $USER; $usercontext = get_context_instance(CONTEXT_USER, $user->id); // User context } else { $select = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT u.*, {$select}\n FROM {user} u\n JOIN {context} ctx ON u.id = ctx.instanceid\n WHERE u.id = :userid AND ctx.contextlevel = :contextlevel"; $params = array('userid' => $userid, 'contextlevel' => CONTEXT_USER); $user = $DB->get_record_sql($sql, $params, IGNORE_MISSING); if (!$user) { return false; } context_helper::preload_from_record($user); // Check that the user can view the profile $usercontext = get_context_instance(CONTEXT_USER, $user->id); // User context $canviewuser = has_capability('moodle/user:viewdetails', $usercontext); if ($course->id == $SITE->id) { if ($CFG->forceloginforprofiles && !has_coursecontact_role($user->id) && !$canviewuser) { // Reduce possibility of "browsing" userbase at site level // Teachers can browse and be browsed at site level. If not forceloginforprofiles, allow access (bug #4366) return false; } } else { $canviewusercourse = has_capability('moodle/user:viewdetails', $coursecontext); $canaccessallgroups = has_capability('moodle/site:accessallgroups', $coursecontext); if (!$canviewusercourse && !$canviewuser || !can_access_course($course, $user->id)) { return false; } if (!$canaccessallgroups && groups_get_course_groupmode($course) == SEPARATEGROUPS) { // If groups are in use, make sure we can see that group return false; } } } $fullname = fullname($user, has_capability('moodle/site:viewfullnames', $this->page->context)); $key = $gstitle; if ($gstitle != 'usercurrentsettings') { $key .= $userid; } // Add a user setting branch $usersetting = $this->add(get_string($gstitle, 'moodle', $fullname), null, self::TYPE_CONTAINER, null, $key); $usersetting->id = 'usersettings'; if ($this->page->context->contextlevel == CONTEXT_USER && $this->page->context->instanceid == $user->id) { // Automatically start by making it active $usersetting->make_active(); } // Check if the user has been deleted if ($user->deleted) { if (!has_capability('moodle/user:update', $coursecontext)) { // We can't edit the user so just show the user deleted message $usersetting->add(get_string('userdeleted'), null, self::TYPE_SETTING); } else { // We can edit the user so show the user deleted message and link it to the profile if ($course->id == $SITE->id) { $profileurl = new moodle_url('/user/profile.php', array('id' => $user->id)); } else { $profileurl = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id)); } $usersetting->add(get_string('userdeleted'), $profileurl, self::TYPE_SETTING); } return true; } $userauthplugin = false; if (!empty($user->auth)) { $userauthplugin = get_auth_plugin($user->auth); } // Add the profile edit link if (isloggedin() && !isguestuser($user) && !is_mnet_remote_user($user)) { if (($currentuser || is_siteadmin($USER) || !is_siteadmin($user)) && has_capability('moodle/user:update', $systemcontext)) { $url = new moodle_url('/user/editadvanced.php', array('id' => $user->id, 'course' => $course->id)); $usersetting->add(get_string('editmyprofile'), $url, self::TYPE_SETTING); } else { if (has_capability('moodle/user:editprofile', $usercontext) && !is_siteadmin($user) || $currentuser && has_capability('moodle/user:editownprofile', $systemcontext)) { if ($userauthplugin && $userauthplugin->can_edit_profile()) { $url = $userauthplugin->edit_profile_url(); if (empty($url)) { $url = new moodle_url('/user/edit.php', array('id' => $user->id, 'course' => $course->id)); } $usersetting->add(get_string('editmyprofile'), $url, self::TYPE_SETTING); } } } } // Change password link if ($userauthplugin && $currentuser && !session_is_loggedinas() && !isguestuser() && has_capability('moodle/user:changeownpassword', $systemcontext) && $userauthplugin->can_change_password()) { $passwordchangeurl = $userauthplugin->change_password_url(); if (empty($passwordchangeurl)) { $passwordchangeurl = new moodle_url('/login/change_password.php', array('id' => $course->id)); } $usersetting->add(get_string("changepassword"), $passwordchangeurl, self::TYPE_SETTING); } // View the roles settings if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override', 'moodle/role:manage'), $usercontext)) { $roles = $usersetting->add(get_string('roles'), null, self::TYPE_SETTING); $url = new moodle_url('/admin/roles/usersroles.php', array('userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('thisusersroles', 'role'), $url, self::TYPE_SETTING); $assignableroles = get_assignable_roles($usercontext, ROLENAME_BOTH); if (!empty($assignableroles)) { $url = new moodle_url('/admin/roles/assign.php', array('contextid' => $usercontext->id, 'userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('assignrolesrelativetothisuser', 'role'), $url, self::TYPE_SETTING); } if (has_capability('moodle/role:review', $usercontext) || count(get_overridable_roles($usercontext, ROLENAME_BOTH)) > 0) { $url = new moodle_url('/admin/roles/permissions.php', array('contextid' => $usercontext->id, 'userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('permissions', 'role'), $url, self::TYPE_SETTING); } $url = new moodle_url('/admin/roles/check.php', array('contextid' => $usercontext->id, 'userid' => $user->id, 'courseid' => $course->id)); $roles->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING); } // Portfolio if ($currentuser && !empty($CFG->enableportfolios) && has_capability('moodle/portfolio:export', $systemcontext)) { require_once $CFG->libdir . '/portfoliolib.php'; if (portfolio_instances(true, false)) { $portfolio = $usersetting->add(get_string('portfolios', 'portfolio'), null, self::TYPE_SETTING); $url = new moodle_url('/user/portfolio.php', array('courseid' => $course->id)); $portfolio->add(get_string('configure', 'portfolio'), $url, self::TYPE_SETTING); $url = new moodle_url('/user/portfoliologs.php', array('courseid' => $course->id)); $portfolio->add(get_string('logs', 'portfolio'), $url, self::TYPE_SETTING); } } $enablemanagetokens = false; if (!empty($CFG->enablerssfeeds)) { $enablemanagetokens = true; } else { if (!is_siteadmin($USER->id) && !empty($CFG->enablewebservices) && has_capability('moodle/webservice:createtoken', get_system_context())) { $enablemanagetokens = true; } } // Security keys if ($currentuser && $enablemanagetokens) { $url = new moodle_url('/user/managetoken.php', array('sesskey' => sesskey())); $usersetting->add(get_string('securitykeys', 'webservice'), $url, self::TYPE_SETTING); } // Repository if (!$currentuser && $usercontext->contextlevel == CONTEXT_USER) { if (!$this->cache->cached('contexthasrepos' . $usercontext->id)) { require_once $CFG->dirroot . '/repository/lib.php'; $editabletypes = repository::get_editable_types($usercontext); $haseditabletypes = !empty($editabletypes); unset($editabletypes); $this->cache->set('contexthasrepos' . $usercontext->id, $haseditabletypes); } else { $haseditabletypes = $this->cache->{'contexthasrepos' . $usercontext->id}; } if ($haseditabletypes) { $url = new moodle_url('/repository/manage_instances.php', array('contextid' => $usercontext->id)); $usersetting->add(get_string('repositories', 'repository'), $url, self::TYPE_SETTING); } } // Messaging if ($currentuser && has_capability('moodle/user:editownmessageprofile', $systemcontext) || !isguestuser($user) && has_capability('moodle/user:editmessageprofile', $usercontext) && !is_primary_admin($user->id)) { $url = new moodle_url('/message/edit.php', array('id' => $user->id)); $usersetting->add(get_string('editmymessage', 'message'), $url, self::TYPE_SETTING); } // Blogs if ($currentuser && !empty($CFG->bloglevel)) { $blog = $usersetting->add(get_string('blogs', 'blog'), null, navigation_node::TYPE_CONTAINER, null, 'blogs'); $blog->add(get_string('preferences', 'blog'), new moodle_url('/blog/preferences.php'), navigation_node::TYPE_SETTING); if (!empty($CFG->useexternalblogs) && $CFG->maxexternalblogsperuser > 0 && has_capability('moodle/blog:manageexternal', get_context_instance(CONTEXT_SYSTEM))) { $blog->add(get_string('externalblogs', 'blog'), new moodle_url('/blog/external_blogs.php'), navigation_node::TYPE_SETTING); $blog->add(get_string('addnewexternalblog', 'blog'), new moodle_url('/blog/external_blog_edit.php'), navigation_node::TYPE_SETTING); } } // Login as ... if (!$user->deleted and !$currentuser && !session_is_loggedinas() && has_capability('moodle/user:loginas', $coursecontext) && !is_siteadmin($user->id)) { $url = new moodle_url('/course/loginas.php', array('id' => $course->id, 'user' => $user->id, 'sesskey' => sesskey())); $usersetting->add(get_string('loginas'), $url, self::TYPE_SETTING); } return $usersetting; }
function definition() { global $CFG, $DB; $mform = $this->_form; $course = $this->_customdata['course']; $instance = $this->_customdata['instance']; $this->course = $course; if ($instance) { $where = 'WHERE c.id = :courseid'; $params = array('courseid' => $instance->customint1); $existing = array(); } else { $where = ''; $params = array(); $existing = $DB->get_records('enrol', array('enrol' => 'meta', 'courseid' => $course->id), '', 'customint1, id'); } // TODO: this has to be done via ajax or else it will fail very badly on large sites! $courses = array('' => get_string('choosedots')); $select = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $join = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; $plugin = enrol_get_plugin('meta'); $sortorder = 'c.' . $plugin->get_config('coursesort', 'sortorder') . ' ASC'; $sql = "SELECT c.id, c.fullname, c.shortname, c.visible {$select} FROM {course} c {$join} {$where} ORDER BY {$sortorder}"; $rs = $DB->get_recordset_sql($sql, array('contextlevel' => CONTEXT_COURSE) + $params); foreach ($rs as $c) { if ($c->id == SITEID or $c->id == $course->id or isset($existing[$c->id])) { continue; } context_helper::preload_from_record($c); $coursecontext = context_course::instance($c->id); if (!$c->visible and !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { continue; } if (!has_capability('enrol/meta:selectaslinked', $coursecontext)) { continue; } $courses[$c->id] = $coursecontext->get_context_name(false); } $rs->close(); $groups = array(0 => get_string('none')); if (has_capability('moodle/course:managegroups', context_course::instance($course->id))) { $groups[ENROL_META_CREATE_GROUP] = get_string('creategroup', 'enrol_meta'); } foreach (groups_get_all_groups($course->id) as $group) { $groups[$group->id] = format_string($group->name, true, array('context' => context_course::instance($course->id))); } $mform->addElement('header', 'general', get_string('pluginname', 'enrol_meta')); $mform->addElement('select', 'link', get_string('linkedcourse', 'enrol_meta'), $courses); $mform->addRule('link', get_string('required'), 'required', null, 'client'); $mform->addElement('select', 'customint2', get_string('addgroup', 'enrol_meta'), $groups); $mform->addElement('hidden', 'id', null); $mform->setType('id', PARAM_INT); $mform->addElement('hidden', 'enrolid'); $mform->setType('enrolid', PARAM_INT); $data = array('id' => $course->id); if ($instance) { $data['link'] = $instance->customint1; $data['enrolid'] = $instance->id; $data['customint2'] = $instance->customint2; $mform->freeze('link'); $this->add_action_buttons(); } else { $this->add_add_buttons(); } $this->set_data($data); }