/** * 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; } } }
public function test_course_completion() { global $DB; $this->resetAfterTest(); // Enable avaibility. // If not enabled all conditional fields will be ignored. set_config('enableavailability', 1); // Enable course completion. // If not enabled all completion settings will be ignored. set_config('enablecompletion', COMPLETION_ENABLED); $generator = $this->getDataGenerator(); // Create course with completion tracking enabled. $course = $generator->create_course(['enablecompletion' => 1, 'numsections' => 3], ['createsections' => true]); // Enrol user to completion tracking course. $sturole = $DB->get_record('role', array('shortname' => 'student')); $generator->enrol_user($this->user1->id, $course->id, $sturole->id); // Create page with completion marked on view. $page1 = $generator->create_module('page', array('course' => $course->id, 'name' => 'page1 complete on view'), array('completion' => 2, 'completionview' => 1)); $modinfo = get_fast_modinfo($course); $page1cm = $modinfo->get_cm($page1->cmid); // Create page restricted to only show when first page is viewed. $moduleinfo = (object) []; $moduleinfo->course = $course->id; $moduleinfo->name = 'page2 available after page1 viewed'; $moduleinfo->availability = json_encode(\core_availability\tree::get_root_json([\availability_completion\condition::get_json($page1->cmid, COMPLETION_COMPLETE)], '&')); $page2 = $generator->create_module('page', $moduleinfo); // Make section 2 restricted to only show when first page is viewed. $section = $modinfo->get_section_info(2); $sectionupdate = ['id' => $section->id, 'availability' => json_encode(\core_availability\tree::get_root_json([\availability_completion\condition::get_json($page1->cmid, COMPLETION_COMPLETE)], '&'))]; $DB->update_record('course_sections', $sectionupdate); // Check user1 has expected unavailable section and mod. $this->setUser($this->user1); // Dump cache and reget modinfo. get_fast_modinfo($course, 0, true); $modinfo = get_fast_modinfo($course); $page2cm = $modinfo->get_cm($page2->cmid); list($previouslyunavailablesections, $previouslyunavailablemods) = local::conditionally_unavailable_elements($course); $this->assertContains(2, $previouslyunavailablesections); $this->assertContains($page2cm->id, $previouslyunavailablemods); // View page1 to trigger completion $context = context_module::instance($page1->cmid); page_view($page1, $course, $page1cm, $context); $completion = new completion_info($course); $completiondata = $completion->get_data($page1cm); $this->assertEquals(COMPLETION_COMPLETE, $completiondata->completionstate); get_fast_modinfo($course, 0, true); // Reset modinfo. // Make sure that unavailable sections and mods no longer contain the ones requiring availabililty criteria // satisfying. list($unavailablesections, $unavailablemods) = local::conditionally_unavailable_elements($course); $this->assertNotContains($page2cm->id, $unavailablemods); $this->assertNotContains(2, $unavailablesections); $result = $this->courseservice->course_completion($course->shortname, $previouslyunavailablesections, $previouslyunavailablemods); // Make sure that the second page module (which is now newly available) appears in the list of newly available // module html. $this->assertTrue(isset($result['newlyavailablemodhtml'][$page2->cmid])); // Make sure that the second section (which is now wnely available) appears in the list of newly available // section html. $this->assertTrue(isset($result['newlyavailablesectionhtml'][2])); }
/** * Get coursecompletion data by course shortname. * @param string $shortname * @param array $previouslyunavailablesections * @param array $previouslyunavailablemods * @return array */ public function course_completion($shortname, $previouslyunavailablesections, $previouslyunavailablemods) { global $PAGE, $OUTPUT; $course = $this->coursebyshortname($shortname); list($unavailablesections, $unavailablemods) = local::conditionally_unavailable_elements($course); $newlyavailablesections = array_diff($previouslyunavailablesections, $unavailablesections); $newlyavailablemods = array_diff($previouslyunavailablemods, $unavailablemods); /** @var \theme_snap_core_course_renderer $courserenderer */ $courserenderer = $PAGE->get_renderer('core', 'course', RENDERER_TARGET_GENERAL); $newlyavailablesectionhtml = []; if (!empty($newlyavailablesections)) { foreach ($newlyavailablesections as $sectionnumber) { $html = $courserenderer->course_section_cm_list($course, $sectionnumber, $sectionnumber); $newlyavailablesectionhtml[$sectionnumber] = $html; } } $newlyavailablemodhtml = []; if (!empty($newlyavailablemods)) { $modinfo = get_fast_modinfo($course); foreach ($newlyavailablemods as $modid) { $completioninfo = new \completion_info($course); $cm = $modinfo->get_cm($modid); if (isset($newlyavailablesectionhtml[$cm->sectionnum])) { // This module's html has already been included in a newly available section. continue; } $html = $courserenderer->course_section_cm_list_item($course, $completioninfo, $cm, $cm->sectionnum); $newlyavailablemodhtml[$modid] = $html; } } $unavailablesections = implode(',', $unavailablesections); $unavailablemods = implode(',', $unavailablemods); $toc = new course_toc($course); return ['unavailablesections' => $unavailablesections, 'unavailablemods' => $unavailablemods, 'newlyavailablemodhtml' => $newlyavailablemodhtml, 'newlyavailablesectionhtml' => $newlyavailablesectionhtml, 'toc' => $toc->export_for_template($OUTPUT)]; }