/** * Tests constructing and using date condition as part of tree. */ public function test_in_tree() { global $SITE, $USER, $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Set server timezone for test. (Important as otherwise the timezone // could be anything - this is modified by other unit tests, too.) $this->setTimezone('UTC'); // SEt user to GMT+5. $USER->timezone = 5; // Construct tree with date condition. $time = strtotime('2014-02-18 14:20:00 GMT'); $structure = (object) array('op' => '|', 'show' => true, 'c' => array((object) array('type' => 'date', 'd' => '>=', 't' => $time))); $tree = new \core_availability\tree($structure); $info = new \core_availability\mock_info(); // Check if available (when not available). condition::set_current_time_for_test($time - 1); $information = ''; $result = $tree->check_available(false, $info, true, $USER->id); $this->assertFalse($result->is_available()); $information = $tree->get_result_information($info, $result); // Note: PM is normally upper-case, but an issue with PHP on Mac means // that on that platform, it is reported lower-case. $this->assertRegExp('~from.*18 February 2014, 7:20 (PM|pm)~', $information); // Check if available (when available). condition::set_current_time_for_test($time); $result = $tree->check_available(false, $info, true, $USER->id); $this->assertTrue($result->is_available()); $information = $tree->get_result_information($info, $result); $this->assertEquals('', $information); }
/** * Tests constructing and using condition as part of tree. */ public function test_in_tree() { global $USER, $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create course with completion turned on and a Page. $CFG->enablecompletion = true; $CFG->enableavailability = true; $generator = $this->getDataGenerator(); $course = $generator->create_course(array('enablecompletion' => 1)); $page = $generator->get_plugin_generator('mod_page')->create_instance(array('course' => $course->id, 'completion' => COMPLETION_TRACKING_MANUAL)); $modinfo = get_fast_modinfo($course); $cm = $modinfo->get_cm($page->cmid); $info = new \core_availability\mock_info($course, $USER->id); $structure = (object) array('op' => '|', 'show' => true, 'c' => array((object) array('type' => 'completion', 'cm' => (int) $cm->id, 'e' => COMPLETION_COMPLETE))); $tree = new \core_availability\tree($structure); // Initial check (user has not completed activity). $result = $tree->check_available(false, $info, true, $USER->id); $this->assertFalse($result->is_available()); // Mark activity complete. $completion = new completion_info($course); $completion->update_state($cm, COMPLETION_COMPLETE); // Now it's true! $result = $tree->check_available(false, $info, true, $USER->id); $this->assertTrue($result->is_available()); }
/** * Tests constructing and using date condition as part of tree. */ public function test_in_tree() { global $USER; $this->setAdminUser(); $info = new \core_availability\mock_info(); $structure = (object) array('op' => '|', 'show' => true, 'c' => array((object) array('type' => 'profile', 'op' => condition::OP_IS_EQUAL_TO, 'cf' => 'frogtype', 'v' => 'tree'))); $tree = new \core_availability\tree($structure); // Initial check (user does not have custom field). $result = $tree->check_available(false, $info, true, $USER->id); $this->assertFalse($result->is_available()); // Set field. $this->set_field($USER->id, 'tree'); // Now it's true! $result = $tree->check_available(false, $info, true, $USER->id); $this->assertTrue($result->is_available()); }
function content_unlock_satisfies_conditions($conditions, $courseid, $userid) { global $DB; if (isset($conditions)) { $tree = new \core_availability\tree(json_decode($conditions)); $course = $DB->get_record('course', array('id' => $courseid)); $info = new content_unlock_conditions_info($course); $result = $tree->check_available(false, $info, true, $userid); return $result->is_available(); } return true; }
/** * Update the module info. * This function doesn't check the user capabilities. It updates the course module and the module instance. * Then execute common action to create/update module process (trigger event, rebuild cache, save plagiarism settings...). * * @param object $cm course module * @param object $moduleinfo module info * @param object $course course of the module * @param object $mform - the mform is required by some specific module in the function MODULE_update_instance(). This is due to a hack in this function. * @return array list of course module and module info. */ function update_moduleinfo($cm, $moduleinfo, $course, $mform = null) { global $DB, $CFG; // Attempt to include module library before we make any changes to DB. include_modulelib($moduleinfo->modulename); $moduleinfo->course = $course->id; $moduleinfo = set_moduleinfo_defaults($moduleinfo); if (!empty($course->groupmodeforce) or !isset($moduleinfo->groupmode)) { $moduleinfo->groupmode = $cm->groupmode; // Keep original. } // Update course module first. $cm->groupmode = $moduleinfo->groupmode; if (isset($moduleinfo->groupingid)) { $cm->groupingid = $moduleinfo->groupingid; } $completion = new completion_info($course); if ($completion->is_enabled() && !empty($moduleinfo->completionunlocked)) { // Update completion settings. $cm->completion = $moduleinfo->completion; $cm->completiongradeitemnumber = $moduleinfo->completiongradeitemnumber; $cm->completionview = $moduleinfo->completionview; $cm->completionexpected = $moduleinfo->completionexpected; } if (!empty($CFG->enableavailability)) { // This code is used both when submitting the form, which uses a long // name to avoid clashes, and by unit test code which uses the real // name in the table. if (property_exists($moduleinfo, 'availabilityconditionsjson')) { if ($moduleinfo->availabilityconditionsjson !== '') { $cm->availability = $moduleinfo->availabilityconditionsjson; } else { $cm->availability = null; } } else { if (property_exists($moduleinfo, 'availability')) { $cm->availability = $moduleinfo->availability; } } // If there is any availability data, verify it. if ($cm->availability) { $tree = new \core_availability\tree(json_decode($cm->availability)); // Save time and database space by setting null if the only data // is an empty tree. if ($tree->is_empty()) { $cm->availability = null; } } } if (isset($moduleinfo->showdescription)) { $cm->showdescription = $moduleinfo->showdescription; } else { $cm->showdescription = 0; } $DB->update_record('course_modules', $cm); $modcontext = context_module::instance($moduleinfo->coursemodule); // Update embedded links and save files. if (plugin_supports('mod', $moduleinfo->modulename, FEATURE_MOD_INTRO, true)) { $moduleinfo->intro = file_save_draft_area_files($moduleinfo->introeditor['itemid'], $modcontext->id, 'mod_' . $moduleinfo->modulename, 'intro', 0, array('subdirs' => true), $moduleinfo->introeditor['text']); $moduleinfo->introformat = $moduleinfo->introeditor['format']; unset($moduleinfo->introeditor); } $updateinstancefunction = $moduleinfo->modulename . "_update_instance"; if (!$updateinstancefunction($moduleinfo, $mform)) { print_error('cannotupdatemod', '', course_get_url($course, $cw->section), $moduleinfo->modulename); } // Make sure visibility is set correctly (in particular in calendar). if (has_capability('moodle/course:activityvisibility', $modcontext)) { set_coursemodule_visible($moduleinfo->coursemodule, $moduleinfo->visible); } if (isset($moduleinfo->cmidnumber)) { // Label. // Set cm idnumber - uniqueness is already verified by form validation. set_coursemodule_idnumber($moduleinfo->coursemodule, $moduleinfo->cmidnumber); } // Now that module is fully updated, also update completion data if required. // (this will wipe all user completion data and recalculate it) if ($completion->is_enabled() && !empty($moduleinfo->completionunlocked)) { $completion->reset_all_state($cm); } $cm->name = $moduleinfo->name; \core\event\course_module_updated::create_from_cm($cm, $modcontext)->trigger(); $moduleinfo = edit_module_post_actions($moduleinfo, $course); return array($cm, $moduleinfo); }
/** * Update the module info. * This function doesn't check the user capabilities. It updates the course module and the module instance. * Then execute common action to create/update module process (trigger event, rebuild cache, save plagiarism settings...). * * @param object $cm course module * @param object $moduleinfo module info * @param object $course course of the module * @param object $mform - the mform is required by some specific module in the function MODULE_update_instance(). This is due to a hack in this function. * @return array list of course module and module info. */ function update_moduleinfo($cm, $moduleinfo, $course, $mform = null) { global $DB, $CFG; $data = new stdClass(); if ($mform) { $data = $mform->get_data(); } // Attempt to include module library before we make any changes to DB. include_modulelib($moduleinfo->modulename); $moduleinfo->course = $course->id; $moduleinfo = set_moduleinfo_defaults($moduleinfo); if (!empty($course->groupmodeforce) or !isset($moduleinfo->groupmode)) { $moduleinfo->groupmode = $cm->groupmode; // Keep original. } // Update course module first. $cm->groupmode = $moduleinfo->groupmode; if (isset($moduleinfo->groupingid)) { $cm->groupingid = $moduleinfo->groupingid; } $completion = new completion_info($course); if ($completion->is_enabled()) { // Completion settings that would affect users who have already completed // the activity may be locked; if so, these should not be updated. if (!empty($moduleinfo->completionunlocked)) { $cm->completion = $moduleinfo->completion; $cm->completiongradeitemnumber = $moduleinfo->completiongradeitemnumber; $cm->completionview = $moduleinfo->completionview; } // The expected date does not affect users who have completed the activity, // so it is safe to update it regardless of the lock status. $cm->completionexpected = $moduleinfo->completionexpected; } if (!empty($CFG->enableavailability)) { // This code is used both when submitting the form, which uses a long // name to avoid clashes, and by unit test code which uses the real // name in the table. if (property_exists($moduleinfo, 'availabilityconditionsjson')) { if ($moduleinfo->availabilityconditionsjson !== '') { $cm->availability = $moduleinfo->availabilityconditionsjson; } else { $cm->availability = null; } } else { if (property_exists($moduleinfo, 'availability')) { $cm->availability = $moduleinfo->availability; } } // If there is any availability data, verify it. if ($cm->availability) { $tree = new \core_availability\tree(json_decode($cm->availability)); // Save time and database space by setting null if the only data // is an empty tree. if ($tree->is_empty()) { $cm->availability = null; } } } if (isset($moduleinfo->showdescription)) { $cm->showdescription = $moduleinfo->showdescription; } else { $cm->showdescription = 0; } $DB->update_record('course_modules', $cm); $modcontext = context_module::instance($moduleinfo->coursemodule); // Update embedded links and save files. if (plugin_supports('mod', $moduleinfo->modulename, FEATURE_MOD_INTRO, true)) { $moduleinfo->intro = file_save_draft_area_files($moduleinfo->introeditor['itemid'], $modcontext->id, 'mod_' . $moduleinfo->modulename, 'intro', 0, array('subdirs' => true), $moduleinfo->introeditor['text']); $moduleinfo->introformat = $moduleinfo->introeditor['format']; unset($moduleinfo->introeditor); } // Get the a copy of the grade_item before it is modified incase we need to scale the grades. $oldgradeitem = null; $newgradeitem = null; if (!empty($data->grade_rescalegrades) && $data->grade_rescalegrades == 'yes') { // Fetch the grade item before it is updated. $oldgradeitem = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => $moduleinfo->modulename, 'iteminstance' => $moduleinfo->instance, 'itemnumber' => 0, 'courseid' => $moduleinfo->course)); } $updateinstancefunction = $moduleinfo->modulename . "_update_instance"; if (!$updateinstancefunction($moduleinfo, $mform)) { print_error('cannotupdatemod', '', course_get_url($course, $cm->section), $moduleinfo->modulename); } // This needs to happen AFTER the grademin/grademax have already been updated. if (!empty($data->grade_rescalegrades) && $data->grade_rescalegrades == 'yes') { // Get the grade_item after the update call the activity to scale the grades. $newgradeitem = grade_item::fetch(array('itemtype' => 'mod', 'itemmodule' => $moduleinfo->modulename, 'iteminstance' => $moduleinfo->instance, 'itemnumber' => 0, 'courseid' => $moduleinfo->course)); if ($newgradeitem && $oldgradeitem->gradetype == GRADE_TYPE_VALUE && $newgradeitem->gradetype == GRADE_TYPE_VALUE) { $params = array($course, $cm, $oldgradeitem->grademin, $oldgradeitem->grademax, $newgradeitem->grademin, $newgradeitem->grademax); if (!component_callback('mod_' . $moduleinfo->modulename, 'rescale_activity_grades', $params)) { print_error('cannotreprocessgrades', '', course_get_url($course, $cm->section), $moduleinfo->modulename); } } } // Make sure visibility is set correctly (in particular in calendar). if (has_capability('moodle/course:activityvisibility', $modcontext)) { set_coursemodule_visible($moduleinfo->coursemodule, $moduleinfo->visible); } if (isset($moduleinfo->cmidnumber)) { // Label. // Set cm idnumber - uniqueness is already verified by form validation. set_coursemodule_idnumber($moduleinfo->coursemodule, $moduleinfo->cmidnumber); } // Update module tags. if (core_tag_tag::is_enabled('core', 'course_modules') && isset($moduleinfo->tags)) { core_tag_tag::set_item_tags('core', 'course_modules', $moduleinfo->coursemodule, $modcontext, $moduleinfo->tags); } // Now that module is fully updated, also update completion data if required. // (this will wipe all user completion data and recalculate it) if ($completion->is_enabled() && !empty($moduleinfo->completionunlocked)) { $completion->reset_all_state($cm); } $cm->name = $moduleinfo->name; \core\event\course_module_updated::create_from_cm($cm, $modcontext)->trigger(); $moduleinfo = edit_module_post_actions($moduleinfo, $course); return array($cm, $moduleinfo); }
/** * Tests the filter_users function. */ public function test_filter_users() { $info = new \core_availability\mock_info(); $checker = new capability_checker($info->get_context()); // Don't need to create real users in database, just use these ids. $users = array(1 => null, 2 => null, 3 => null); // Test basic tree with one condition that doesn't filter. $structure = self::tree(array(self::mock(array()))); $tree = new \core_availability\tree($structure); $result = $tree->filter_user_list($users, false, $info, $checker); ksort($result); $this->assertEquals(array(1, 2, 3), array_keys($result)); // Now a tree with one condition that filters. $structure = self::tree(array(self::mock(array('filter' => array(2, 3))))); $tree = new \core_availability\tree($structure); $result = $tree->filter_user_list($users, false, $info, $checker); ksort($result); $this->assertEquals(array(2, 3), array_keys($result)); // Tree with two conditions that both filter (|). $structure = self::tree(array(self::mock(array('filter' => array(3))), self::mock(array('filter' => array(1))))); $tree = new \core_availability\tree($structure); $result = $tree->filter_user_list($users, false, $info, $checker); ksort($result); $this->assertEquals(array(1, 3), array_keys($result)); // Tree with two condition that both filter (&). $structure = self::tree(array(self::mock(array('filter' => array(2, 3))), self::mock(array('filter' => array(1, 2)))), '&', false, array(true, true)); $tree = new \core_availability\tree($structure); $result = $tree->filter_user_list($users, false, $info, $checker); ksort($result); $this->assertEquals(array(2), array_keys($result)); // Tree with child tree with NOT condition. $structure = self::tree(array(self::tree(self::mock(array('filter' => array(1))), '!&', null))); $tree = new \core_availability\tree($structure); $result = $tree->filter_user_list($users, false, $info, $checker); ksort($result); $this->assertEquals(array(2, 3), array_keys($result)); }