/** * If dynamic data for this course-module is not yet available, gets it. * * This function is automatically called when requesting any course_modinfo property * that can be modified by modules (have a set_xxx method). * * Dynamic data is data which does not come directly from the cache but is calculated at * runtime based on the current user. Primarily this concerns whether the user can access * the module or not. * * As part of this function, the module's _cm_info_dynamic function from its lib.php will * be called (if it exists). * @return void */ private function obtain_dynamic_data() { global $CFG; $userid = $this->modinfo->get_user_id(); if ($this->state >= self::STATE_BUILDING_DYNAMIC || $userid == -1) { return; } $this->state = self::STATE_BUILDING_DYNAMIC; if (!empty($CFG->enableavailability)) { require_once $CFG->libdir . '/conditionlib.php'; // Get availability information. $ci = new \core_availability\info_module($this); // Note that the modinfo currently available only includes minimal details (basic data) // but we know that this function does not need anything more than basic data. $this->available = $ci->is_available($this->availableinfo, true, $userid, $this->modinfo); // Check parent section $parentsection = $this->modinfo->get_section_info($this->sectionnum); if (!$parentsection->available) { // Do not store info from section here, as that is already // presented from the section (if appropriate) - just change // the flag $this->available = false; } } else { $this->available = true; } // Update visible state for current user $this->update_user_visible(); // Let module make dynamic changes at this point $this->call_mod_function('cm_info_dynamic'); $this->state = self::STATE_DYNAMIC; }
/** * Tests constructing and using condition. */ public function test_usage() { global $CFG, $USER; $this->resetAfterTest(); $CFG->enableavailability = true; // Erase static cache before test. condition::wipe_static_cache(); // Make a test course and user. $generator = $this->getDataGenerator(); $course = $generator->create_course(); $user = $generator->create_user(); $generator->enrol_user($user->id, $course->id); $info = new \core_availability\mock_info($course, $user->id); // Make a test grouping and group. $grouping = $generator->create_grouping(array('courseid' => $course->id, 'name' => 'Grouping!')); $group = $generator->create_group(array('courseid' => $course->id)); groups_assign_grouping($grouping->id, $group->id); // Do test (not in grouping). $structure = (object) array('type' => 'grouping', 'id' => (int) $grouping->id); $cond = new condition($structure); // Check if available (when not available). $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $this->assertRegExp('~belong to a group in.*Grouping!~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // Add user to grouping and refresh cache. groups_add_member($group, $user); get_fast_modinfo($course->id, 0, true); // Recheck. $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $this->assertRegExp('~do not belong to a group in.*Grouping!~', $information); // Admin user doesn't belong to the grouping, but they can access it // either way (positive or NOT) because of accessallgroups. $this->setAdminUser(); $infoadmin = new \core_availability\mock_info($course, $USER->id); $this->assertTrue($cond->is_available(false, $infoadmin, true, $USER->id)); $this->assertTrue($cond->is_available(true, $infoadmin, true, $USER->id)); // Grouping that doesn't exist uses 'missing' text. $cond = new condition((object) array('id' => $grouping->id + 1000)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $this->assertRegExp('~belong to a group in.*(Missing grouping)~', $information); // We need an actual cm object to test the 'grouping from cm' option. $pagegen = $generator->get_plugin_generator('mod_page'); $page = $pagegen->create_instance(array('course' => $course->id, 'groupingid' => $grouping->id, 'availability' => '{"op":"|","show":true,"c":[{"type":"grouping","activity":true}]}')); rebuild_course_cache($course->id, true); // Check if available using the 'from course-module' grouping option. $modinfo = get_fast_modinfo($course, $user->id); $cm = $modinfo->get_cm($page->cmid); $info = new \core_availability\info_module($cm); $information = ''; $this->assertTrue($info->is_available($information, false, $user->id)); // Remove user from grouping again and recheck. groups_remove_member($group, $user); get_fast_modinfo($course->id, 0, true); $this->assertFalse($info->is_available($information, false, $user->id)); $this->assertRegExp('~belong to a group in.*Grouping!~', $information); }
/** * Return conditionally unavailable elements. * @param $course * @return array * @throws \coding_exception */ public static function conditionally_unavailable_elements($course) { $cancomplete = isloggedin() && !isguestuser(); $unavailablesections = []; $unavailablemods = []; $information = ''; if ($cancomplete) { $completioninfo = new \completion_info($course); if ($completioninfo->is_enabled()) { $modinfo = get_fast_modinfo($course); $sections = $modinfo->get_section_info_all(); foreach ($sections as $number => $section) { $ci = new \core_availability\info_section($section); if (!$ci->is_available($information, true)) { $unavailablesections[] = $number; } } foreach ($modinfo->get_cms() as $mod) { $ci = new \core_availability\info_module($mod); if (!$ci->is_available($information, true)) { $unavailablemods[] = $mod->id; } } } } return [$unavailablesections, $unavailablemods]; }
/** * Checks whether a user can be subscribed to the forum, regardless of * subscription option. Includes a variety of other checks. [These are * supposed to be the same as checks done when building the list of people * for email.] * @param int $userid User ID or 0 for current * @return bool True if user can be subscribed */ private function can_be_subscribed($userid = 0) { global $USER, $CFG; $userid = mod_forumng_utils::get_real_userid($userid); $cm = $this->get_course_module(); $course = $this->get_course(); $context = $this->get_context(); // Guests cannot subscribe if (!isloggedin() || isguestuser($userid)) { return false; } // Get from cache if possible if (!isset($this->cache->can_be_subscribed)) { $this->cache->can_be_subscribed = array(); } if (array_key_exists($userid, $this->cache->can_be_subscribed)) { return $this->cache->can_be_subscribed[$userid]; } // This is not a loop, just so I can use break do { // Check user can see forum if (!has_capability('mod/forumng:viewdiscussion', $context, $userid)) { $result = false; break; } // For current user, can take shortcut if ($userid == $USER->id) { if (empty($cm->uservisible)) { $uservisible = false; } else { $uservisible = true; } if (!$uservisible) { $result = false; break; } } else { $visible = $cm->visible; $info = new \core_availability\info_module($cm); $visible = $visible && $info->is_available($crap, false, $userid); if (!$visible && !has_capability('moodle/site:viewhiddenactivities', $context, $userid)) { $result = false; break; } } if ($this->get_group_mode() == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $context, $userid)) { // Limit it to people within groups in the grouping, if one is selected. $groupobjs = groups_get_all_groups($course->id, $userid, $cm->groupingid, 'g.id'); if (!$groupobjs || count($groupobjs) == 0) { $result = false; break; } } $result = true; break; } while (false); $this->cache->can_be_subscribed[$userid] = $result; return $result; }
/** * Javascript required by both standard header layout and flexpage layout * * @return void */ public static function page_requires_js() { global $CFG, $PAGE, $COURSE, $USER; $PAGE->requires->jquery(); $PAGE->requires->strings_for_js(array('close', 'debugerrors', 'problemsfound', 'error:coverimageexceedsmaxbytes', 'error:coverimageresolutionlow', 'forumtopic', 'forumauthor', 'forumpicturegroup', 'forumreplies', 'forumlastpost', 'hiddencoursestoggle', 'loading', 'more', 'moving', 'movingcount', 'movehere', 'movefailed', 'movingdropsectionhelp', 'movingstartedhelp'), 'theme_snap'); $PAGE->requires->strings_for_js(['ok', 'cancel'], 'moodle'); $PAGE->requires->strings_for_js(['printbook'], 'booktool_print'); // Are we viewing /course/view.php - note, this is different from just checking the page type. // We only ever want to load course.js when on site page or view.php - no point in loading it when on // course settings page, etc. $courseviewpage = local::current_url_path() === '/course/view.php'; $pagehascoursecontent = $PAGE->pagetype === 'site-index' || $courseviewpage; $cancomplete = isloggedin() && !isguestuser(); $unavailablesections = []; $unavailablemods = []; if ($cancomplete) { $completioninfo = new \completion_info($COURSE); if ($completioninfo->is_enabled()) { $modinfo = get_fast_modinfo($COURSE); $sections = $modinfo->get_section_info_all(); foreach ($sections as $number => $section) { $ci = new \core_availability\info_section($section); $information = ''; if (!$ci->is_available($information, true)) { $unavailablesections[] = $number; } } foreach ($modinfo as $mod) { $ci = new \core_availability\info_module($mod); if (!$ci->is_available($information, true)) { $unavailablemods[] = $mod->id; } } } } list($unavailablesections, $unavailablemods) = local::conditionally_unavailable_elements($COURSE); $coursevars = (object) ['id' => $COURSE->id, 'shortname' => $COURSE->shortname, 'contextid' => $PAGE->context->id, 'ajaxurl' => '/course/rest.php', 'unavailablesections' => $unavailablesections, 'unavailablemods' => $unavailablemods, 'enablecompletion' => $COURSE->enablecompletion]; $initvars = [$coursevars, $pagehascoursecontent, get_max_upload_file_size($CFG->maxbytes)]; $PAGE->requires->js_call_amd('theme_snap/snap', 'snapInit', $initvars); // Does the page have editable course content? if ($pagehascoursecontent && $PAGE->user_allowed_editing()) { $canmanageacts = has_capability('moodle/course:manageactivities', context_course::instance($COURSE->id)); if ($canmanageacts && empty($USER->editing)) { $modinfo = get_fast_modinfo($COURSE); $modnamesused = $modinfo->get_used_module_names(); // Temporarily change edit mode to on for course ajax to be included. $USER->editing = true; self::include_course_ajax($COURSE, $modnamesused); $USER->editing = false; } } }