protected function define_execution() { global $CFG, $DB; // Note: This code runs even if availability is disabled when restoring. // That will ensure that if you later turn availability on for the site, // there will be no incorrect IDs. (It doesn't take long if the restored // data does not contain any availability information.) // Get modinfo with all data after resetting cache. rebuild_course_cache($this->get_courseid(), true); $modinfo = get_fast_modinfo($this->get_courseid()); // Update all sections that were restored. $params = array('backupid' => $this->get_restoreid(), 'itemname' => 'course_section'); $rs = $DB->get_recordset('backup_ids_temp', $params, '', 'newitemid'); $sectionsbyid = null; foreach ($rs as $rec) { if (is_null($sectionsbyid)) { $sectionsbyid = array(); foreach ($modinfo->get_section_info_all() as $section) { $sectionsbyid[$section->id] = $section; } } if (!array_key_exists($rec->newitemid, $sectionsbyid)) { // If the section was not fully restored for some reason // (e.g. due to an earlier error), skip it. $this->get_logger()->process('Section not fully restored: id ' . $rec->newitemid, backup::LOG_WARNING); continue; } $section = $sectionsbyid[$rec->newitemid]; if (!is_null($section->availability)) { $info = new \core_availability\info_section($section); $info->update_after_restore($this->get_restoreid(), $this->get_courseid(), $this->get_logger()); } } $rs->close(); // Update all modules that were restored. $params = array('backupid' => $this->get_restoreid(), 'itemname' => 'course_module'); $rs = $DB->get_recordset('backup_ids_temp', $params, '', 'newitemid'); foreach ($rs as $rec) { if (!array_key_exists($rec->newitemid, $modinfo->cms)) { // If the module was not fully restored for some reason // (e.g. due to an earlier error), skip it. $this->get_logger()->process('Module not fully restored: id ' . $rec->newitemid, backup::LOG_WARNING); continue; } $cm = $modinfo->get_cm($rec->newitemid); if (!is_null($cm->availability)) { $info = new \core_availability\info_module($cm); $info->update_after_restore($this->get_restoreid(), $this->get_courseid(), $this->get_logger()); } } $rs->close(); }
/** * If section is not visible, display the message about that ('Not available * until...', that sort of thing). Otherwise, returns blank. * * For users with the ability to view hidden sections, it shows the * information even though you can view the section and also may include * slightly fuller information (so that teachers can tell when sections * are going to be unavailable etc). This logic is the same as for * activities. * * @param stdClass $section The course_section entry from DB * @param bool $canviewhidden True if user can view hidden sections * @return string HTML to output */ protected function section_availability_message($section, $canviewhidden) { global $CFG; $o = ''; if (!$section->uservisible) { // Note: We only get to this function if availableinfo is non-empty, // so there is definitely something to print. $formattedinfo = \core_availability\info::format_info($section->availableinfo, $section->course); $o .= html_writer::div($formattedinfo, 'availabilityinfo'); } else { if ($canviewhidden && !empty($CFG->enableavailability) && $section->visible) { $ci = new \core_availability\info_section($section); $fullinfo = $ci->get_full_information(); if ($fullinfo) { $formattedinfo = \core_availability\info::format_info($fullinfo, $section->course); $o .= html_writer::div($formattedinfo, 'availabilityinfo'); } } } return $o; }
/** * Used in course/lib.php because we need to disable the completion JS if * a completion value affects a conditional activity. * * @param \stdClass $course Moodle course object * @param int $cmid Course-module id * @return bool True if this is used in a condition, false otherwise */ public static function completion_value_used($course, $cmid) { // Have we already worked out a list of required completion values // for this course? If so just use that. if (!array_key_exists($course->id, self::$modsusedincondition)) { // We don't have data for this course, build it. $modinfo = get_fast_modinfo($course); self::$modsusedincondition[$course->id] = array(); // Activities. foreach ($modinfo->cms as $othercm) { if (is_null($othercm->availability)) { continue; } $ci = new \core_availability\info_module($othercm); $tree = $ci->get_availability_tree(); foreach ($tree->get_all_children('availability_completion\\condition') as $cond) { self::$modsusedincondition[$course->id][$cond->cmid] = true; } } // Sections. foreach ($modinfo->get_section_info_all() as $section) { if (is_null($section->availability)) { continue; } $ci = new \core_availability\info_section($section); $tree = $ci->get_availability_tree(); foreach ($tree->get_all_children('availability_completion\\condition') as $cond) { self::$modsusedincondition[$course->id][$cond->cmid] = true; } } } return array_key_exists($cmid, self::$modsusedincondition[$course->id]); }
/** * Finds whether this section is available at the moment for the current user. * * The value can be accessed publicly as $sectioninfo->available * * @return bool */ private function get_available() { global $CFG; $userid = $this->modinfo->get_user_id(); if ($this->_available !== null || $userid == -1) { // Has already been calculated or does not need calculation. return $this->_available; } if (!empty($CFG->enableavailability)) { require_once $CFG->libdir . '/conditionlib.php'; // Get availability information. $ci = new \core_availability\info_section($this); $this->_available = $ci->is_available($this->_availableinfo, true, $userid, $this->modinfo); } else { $this->_available = true; $this->_availableinfo = ''; } return $this->_available; }
/** * Finds whether this section is available at the moment for the current user. * * The value can be accessed publicly as $sectioninfo->available * * @return bool */ private function get_available() { global $CFG; $userid = $this->modinfo->get_user_id(); if ($this->_available !== null || $userid == -1) { // Has already been calculated or does not need calculation. return $this->_available; } $this->_available = true; $this->_availableinfo = ''; if (!empty($CFG->enableavailability)) { // Get availability information. $ci = new \core_availability\info_section($this); $this->_available = $ci->is_available($this->_availableinfo, true, $userid, $this->modinfo); } // Execute the hook from the course format that may override the available/availableinfo properties. $currentavailable = $this->_available; course_get_format($this->modinfo->get_course())->section_get_available_hook($this, $this->_available, $this->_availableinfo); if (!$currentavailable && $this->_available) { debugging('section_get_available_hook() can not make unavailable section available', DEBUG_DEVELOPER); $this->_available = $currentavailable; } return $this->_available; }
/** * Changes all date restrictions on a course by the specified shift amount. * Used by the course reset feature. * * @param int $courseid Course id * @param int $timeshift Offset in seconds */ public static function update_all_dates($courseid, $timeshift) { global $DB; $modinfo = get_fast_modinfo($courseid); $anychanged = false; // Adjust dates from all course modules. foreach ($modinfo->cms as $cm) { if (!$cm->availability) { continue; } $info = new \core_availability\info_module($cm); $tree = $info->get_availability_tree(); $dates = $tree->get_all_children('availability_date\\condition'); $changed = false; foreach ($dates as $date) { $date->time += $timeshift; $changed = true; } // Save the updated course module. if ($changed) { $DB->set_field('course_modules', 'availability', json_encode($tree->save()), array('id' => $cm->id)); $anychanged = true; } } // Adjust dates from all course sections. foreach ($modinfo->get_section_info_all() as $section) { if (!$section->availability) { continue; } $info = new \core_availability\info_section($section); $tree = $info->get_availability_tree(); $dates = $tree->get_all_children('availability_date\\condition'); $changed = false; foreach ($dates as $date) { $date->time += $timeshift; $changed = true; } // Save the updated course module. if ($changed) { $DB->set_field('course_sections', 'availability', json_encode($tree->save()), array('id' => $section->id)); $anychanged = true; } } // Ensure course cache is cleared if required. if ($anychanged) { rebuild_course_cache($courseid, true); } }
/** * 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]; }
/** * 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; } } }