MDL-44070 Conditional availability enhancements (6): core changes

Changes core code to use new API instead of the old one when
checking user access to activities and sections.

Includes changes to other libraries that are necessary after
adding the availability system and removing old conditional tables
etc.
This commit is contained in:
sam marshall 2014-03-26 12:01:52 +00:00
parent 6a601097a0
commit 8d1f33e122
14 changed files with 393 additions and 402 deletions

View file

@ -44,8 +44,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
new lang_string('configcompletiondefault', 'completion'), 1, $options));
$optionalsubsystems->add($checkbox = new admin_setting_configcheckbox('enableavailability',
new lang_string('enableavailability','condition'),
new lang_string('configenableavailability','condition'), 0));
new lang_string('enableavailability', 'availability'),
new lang_string('enableavailability_desc', 'availability'), 0));
$checkbox->set_affects_modinfo(true);
$optionalsubsystems->add(new admin_setting_configcheckbox('enableplagiarism', new lang_string('enableplagiarism','plagiarism'), new lang_string('configenableplagiarism','plagiarism'), 0));

View file

@ -165,10 +165,9 @@ class core_course_external extends external_api {
//user that can view hidden module should know about the visibility
$module['visible'] = $cm->visible;
//availability date (also send to user who can see hidden module when the showavailabilyt is ON)
if ($canupdatecourse or ($CFG->enableavailability && $canviewhidden && $cm->showavailability)) {
$module['availablefrom'] = $cm->availablefrom;
$module['availableuntil'] = $cm->availableuntil;
// Availability date (also send to user who can see hidden module).
if ($CFG->enableavailability && ($canviewhidden || $canupdatecourse)) {
$module['availability'] = $cm->availability;
}
$baseurl = 'webservice/pluginfile.php';
@ -223,8 +222,7 @@ class core_course_external extends external_api {
'modicon' => new external_value(PARAM_URL, 'activity icon url'),
'modname' => new external_value(PARAM_PLUGIN, 'activity module type'),
'modplural' => new external_value(PARAM_TEXT, 'activity module plural name'),
'availablefrom' => new external_value(PARAM_INT, 'module availability start date', VALUE_OPTIONAL),
'availableuntil' => new external_value(PARAM_INT, 'module availability en date', VALUE_OPTIONAL),
'availability' => new external_value(PARAM_RAW, 'module availability settings', VALUE_OPTIONAL),
'indent' => new external_value(PARAM_INT, 'number of identation in the site'),
'contents' => new external_multiple_structure(
new external_single_structure(

View file

@ -1056,16 +1056,8 @@ function get_array_of_activities($courseid) {
$rawmods[$seq]->completiongradeitemnumber;
$mod[$seq]->completionview = $rawmods[$seq]->completionview;
$mod[$seq]->completionexpected = $rawmods[$seq]->completionexpected;
$mod[$seq]->availablefrom = $rawmods[$seq]->availablefrom;
$mod[$seq]->availableuntil = $rawmods[$seq]->availableuntil;
$mod[$seq]->showavailability = $rawmods[$seq]->showavailability;
$mod[$seq]->showdescription = $rawmods[$seq]->showdescription;
if (!empty($CFG->enableavailability)) {
condition_info::fill_availability_conditions($rawmods[$seq]);
$mod[$seq]->conditionscompletion = $rawmods[$seq]->conditionscompletion;
$mod[$seq]->conditionsgrade = $rawmods[$seq]->conditionsgrade;
$mod[$seq]->conditionsfield = $rawmods[$seq]->conditionsfield;
}
$mod[$seq]->availability = $rawmods[$seq]->availability;
$modname = $mod[$seq]->mod;
$functionname = $modname."_get_coursemodule_info";
@ -1139,8 +1131,7 @@ function get_array_of_activities($courseid) {
// 'empty'. This list corresponds to code in the cm_info constructor.
foreach (array('idnumber', 'groupmode', 'groupingid', 'groupmembersonly',
'indent', 'completion', 'extra', 'extraclasses', 'iconurl', 'onclick', 'content',
'icon', 'iconcomponent', 'customdata', 'showavailability', 'availablefrom',
'availableuntil', 'conditionscompletion', 'conditionsgrade',
'icon', 'iconcomponent', 'customdata', 'availability',
'completionview', 'completionexpected', 'score', 'showdescription')
as $property) {
if (property_exists($mod[$seq], $property) &&
@ -1698,8 +1689,6 @@ function course_delete_module($cmid) {
// features are not turned on, in case they were turned on previously (these will be
// very quick on an empty table).
$DB->delete_records('course_modules_completion', array('coursemoduleid' => $cm->id));
$DB->delete_records('course_modules_availability', array('coursemoduleid'=> $cm->id));
$DB->delete_records('course_modules_avail_fields', array('coursemoduleid' => $cm->id));
$DB->delete_records('course_completion_criteria', array('moduleinstance' => $cm->id,
'criteriatype' => COMPLETION_CRITERIA_TYPE_ACTIVITY));

View file

@ -220,9 +220,10 @@ class core_course_courselib_testcase extends advanced_testcase {
$moduleinfo->completionexpected = time() + (7 * 24 * 3600);
// Conditional activity.
$moduleinfo->availablefrom = time();
$moduleinfo->availableuntil = time() + (7 * 24 * 3600);
$moduleinfo->showavailability = CONDITION_STUDENTVIEW_SHOW;
$moduleinfo->availability = '{"op":"&","showc":[true,true],"c":[' .
'{"type":"date","d":">=","t":' . time() . '},' .
'{"type":"date","d":"<","t":' . (time() + (7 * 24 * 3600)) . '}' .
']}';
$coursegradeitem = grade_item::fetch_course_item($moduleinfo->course); //the activity will become available only when the user reach some grade into the course itself.
$moduleinfo->conditiongradegroup = array(array('conditiongradeitemid' => $coursegradeitem->id, 'conditiongrademin' => 10, 'conditiongrademax' => 80));
$moduleinfo->conditionfieldgroup = array(array('conditionfield' => 'email', 'conditionfieldoperator' => OP_CONTAINS, 'conditionfieldvalue' => '@'));
@ -280,9 +281,7 @@ class core_course_courselib_testcase extends advanced_testcase {
$this->assertEquals($moduleinfo->completionview, $dbcm->completionview);
$this->assertEquals($moduleinfo->completiongradeitemnumber, $dbcm->completiongradeitemnumber);
$this->assertEquals($moduleinfo->completionexpected, $dbcm->completionexpected);
$this->assertEquals($moduleinfo->availablefrom, $dbcm->availablefrom);
$this->assertEquals($moduleinfo->availableuntil, $dbcm->availableuntil);
$this->assertEquals($moduleinfo->showavailability, $dbcm->showavailability);
$this->assertEquals($moduleinfo->availability, $dbcm->availability);
$this->assertEquals($moduleinfo->showdescription, $dbcm->showdescription);
$this->assertEquals($moduleinfo->groupmode, $dbcm->groupmode);
$this->assertEquals($moduleinfo->cmidnumber, $dbcm->idnumber);
@ -298,25 +297,6 @@ class core_course_courselib_testcase extends advanced_testcase {
$this->assertEquals($moduleinfo->intro, $dbmodinstance->intro);
$this->assertEquals($moduleinfo->introformat, $dbmodinstance->introformat);
// Common values when conditional activity is enabled.
foreach ($moduleinfo->conditionfieldgroup as $fieldgroup) {
$isfieldgroupsaved = $DB->count_records('course_modules_avail_fields', array('coursemoduleid' => $dbcm->id,
'userfield' => $fieldgroup['conditionfield'], 'operator' => $fieldgroup['conditionfieldoperator'],
'value' => $fieldgroup['conditionfieldvalue']));
$this->assertEquals(1, $isfieldgroupsaved);
}
foreach ($moduleinfo->conditiongradegroup as $gradegroup) {
$isgradegroupsaved = $DB->count_records('course_modules_availability', array('coursemoduleid' => $dbcm->id,
'grademin' => $gradegroup['conditiongrademin'], 'grademax' => $gradegroup['conditiongrademax'],
'gradeitemid' => $gradegroup['conditiongradeitemid']));
$this->assertEquals(1, $isgradegroupsaved);
}
foreach ($moduleinfo->conditioncompletiongroup as $completiongroup) {
$iscompletiongroupsaved = $DB->count_records('course_modules_availability', array('coursemoduleid' => $dbcm->id,
'sourcecmid' => $completiongroup['conditionsourcecmid'], 'requiredcompletion' => $completiongroup['conditionrequiredcompletion']));
$this->assertEquals(1, $iscompletiongroupsaved);
}
// Test specific to the module.
$modulerunasserts = $modulename.'_create_run_asserts';
$this->$modulerunasserts($moduleinfo, $dbmodinstance);
@ -478,13 +458,14 @@ class core_course_courselib_testcase extends advanced_testcase {
$moduleinfo->completionunlocked = 1;
// Conditional activity.
$moduleinfo->availablefrom = time();
$moduleinfo->availableuntil = time() + (7 * 24 * 3600);
$moduleinfo->showavailability = CONDITION_STUDENTVIEW_SHOW;
$coursegradeitem = grade_item::fetch_course_item($moduleinfo->course); //the activity will become available only when the user reach some grade into the course itself.
$moduleinfo->conditiongradegroup = array(array('conditiongradeitemid' => $coursegradeitem->id, 'conditiongrademin' => 10, 'conditiongrademax' => 80));
$moduleinfo->conditionfieldgroup = array(array('conditionfield' => 'email', 'conditionfieldoperator' => OP_CONTAINS, 'conditionfieldvalue' => '@'));
$moduleinfo->conditioncompletiongroup = array(array('conditionsourcecmid' => $assigncm->id, 'conditionrequiredcompletion' => COMPLETION_COMPLETE)); // "conditionsourcecmid == 0" => none
$moduleinfo->availability = '{"op":"&","showc":[true,true],"c":[' .
'{"type":"date","d":">=","t":' . time() . '},' .
'{"type":"date","d":"<","t":' . (time() + (7 * 24 * 3600)) . '}' .
'{"type":"grade","id":' . $coursegradeitem->id . ',"min":10,"max":80},' .
'{"type":"profile","sf":"email","op":"contains","v":"@"},'.
'{"type":"completion","id":'. $assigncm->id . ',"e":' . COMPLETION_COMPLETE . '}' .
']}';
// Grading and Advanced grading.
require_once($CFG->dirroot . '/rating/lib.php');
@ -533,9 +514,7 @@ class core_course_courselib_testcase extends advanced_testcase {
$this->assertEquals($moduleinfo->completionview, $dbcm->completionview);
$this->assertEquals($moduleinfo->completiongradeitemnumber, $dbcm->completiongradeitemnumber);
$this->assertEquals($moduleinfo->completionexpected, $dbcm->completionexpected);
$this->assertEquals($moduleinfo->availablefrom, $dbcm->availablefrom);
$this->assertEquals($moduleinfo->availableuntil, $dbcm->availableuntil);
$this->assertEquals($moduleinfo->showavailability, $dbcm->showavailability);
$this->assertEquals($moduleinfo->availability, $dbcm->availability);
$this->assertEquals($moduleinfo->showdescription, $dbcm->showdescription);
$this->assertEquals($moduleinfo->groupmode, $dbcm->groupmode);
$this->assertEquals($moduleinfo->cmidnumber, $dbcm->idnumber);
@ -551,25 +530,6 @@ class core_course_courselib_testcase extends advanced_testcase {
$this->assertEquals($moduleinfo->intro, $dbmodinstance->intro);
$this->assertEquals($moduleinfo->introformat, $dbmodinstance->introformat);
// Common values when conditional activity is enabled.
foreach ($moduleinfo->conditionfieldgroup as $fieldgroup) {
$isfieldgroupsaved = $DB->count_records('course_modules_avail_fields', array('coursemoduleid' => $dbcm->id,
'userfield' => $fieldgroup['conditionfield'], 'operator' => $fieldgroup['conditionfieldoperator'],
'value' => $fieldgroup['conditionfieldvalue']));
$this->assertEquals(1, $isfieldgroupsaved);
}
foreach ($moduleinfo->conditiongradegroup as $gradegroup) {
$isgradegroupsaved = $DB->count_records('course_modules_availability', array('coursemoduleid' => $dbcm->id,
'grademin' => $gradegroup['conditiongrademin'], 'grademax' => $gradegroup['conditiongrademax'],
'gradeitemid' => $gradegroup['conditiongradeitemid']));
$this->assertEquals(1, $isgradegroupsaved);
}
foreach ($moduleinfo->conditioncompletiongroup as $completiongroup) {
$iscompletiongroupsaved = $DB->count_records('course_modules_availability', array('coursemoduleid' => $dbcm->id,
'sourcecmid' => $completiongroup['conditionsourcecmid'], 'requiredcompletion' => $completiongroup['conditionrequiredcompletion']));
$this->assertEquals(1, $iscompletiongroupsaved);
}
// Test specific to the module.
$modulerunasserts = $modulename.'_update_run_asserts';
$this->$modulerunasserts($moduleinfo, $dbmodinstance);

View file

@ -360,16 +360,16 @@ class grade_report_user extends grade_report {
($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_grade->is_hiddenuntil()))) {
$hide = true;
} else if (!empty($grade_object->itemmodule) && !empty($grade_object->iteminstance)) {
// The grade object can be marked visible but still be hidden if...
// 1) "enablegroupmembersonly" is on and the activity is assigned to a grouping the user is not in.
// 2) the student cannot see the activity due to conditional access and its set to be hidden entirely.
// The grade object can be marked visible but still be hidden if
// the student cannot see the activity due to conditional access
// and it's set to be hidden entirely.
$instances = $this->gtree->modinfo->get_instances_of($grade_object->itemmodule);
if (!empty($instances[$grade_object->iteminstance])) {
$cm = $instances[$grade_object->iteminstance];
if (!$cm->uservisible) {
// Further checks are required to determine whether the activity is entirely hidden or just greyed out.
if ($cm->is_user_access_restricted_by_group() || $cm->is_user_access_restricted_by_conditional_access() ||
$cm->is_user_access_restricted_by_capability()) {
// If there is 'availableinfo' text then it is only greyed
// out and not entirely hidden.
if (!$cm->availableinfo) {
$hide = true;
}
}

View file

@ -147,16 +147,17 @@ class core_grade_reportuserlib_testcase extends advanced_testcase {
}
// Conditional activity tests.
$DB->insert_record('course_modules_availability', (object)array(
'coursemoduleid'=>$forum1cm->id,
'gradeitemid' => 37,
'grademin' => 5.5
));
$cm = (object)array('id' => $forum1cm->id);
$test = new condition_info($cm, CONDITION_MISSING_EVERYTHING);
$fullcm = $test->get_full_course_module();
// Note: I have ported this test to the new conditional availability
// system, but it does not appear to actually test anything - in fact,
// if you remove the code that sets the condition, it still passes
// because it apparently is intended to have the same number of rows
// even when some are hidden. The same is true of the
// set_coursemodule_visible test above. I don't feel this is a very
// good test; somebody with more knowledge of this report might want to
// fix it to check that the row actually is being hidden.
$DB->set_field('course_modules', 'availability', '{"op":"|","show":false,"c":[' .
'{"type":"grade","min":5.5,"id":37}]}', array('id' => $forum1cm->id));
get_fast_modinfo($course->id, 0, true);
foreach ($users as $user) {
$this->setUser($user);

View file

@ -1522,6 +1522,11 @@ function get_all_instances_in_course($modulename, $course, $userid=NULL, $includ
* and the module's type (eg "forum") returns whether the object
* is visible or not, groupmembersonly visibility not tested
*
* NOTE: This does NOT take into account visibility to a particular user.
* To get visibility access for a specific user, use get_fast_modinfo, get a
* cm_info object from this, and check the ->uservisible property; or use
* the \core_availability\info_module::is_user_visible() static function.
*
* @global object
* @param $moduletype Name of the module eg 'forum'
@ -1548,46 +1553,6 @@ function instance_is_visible($moduletype, $module) {
return true; // visible by default!
}
/**
* Determine whether a course module is visible within a course,
* this is different from instance_is_visible() - faster and visibility for user
*
* @global object
* @global object
* @uses DEBUG_DEVELOPER
* @uses CONTEXT_MODULE
* @uses CONDITION_MISSING_EXTRATABLE
* @param object $cm object
* @param int $userid empty means current user
* @return bool Success
*/
function coursemodule_visible_for_user($cm, $userid=0) {
global $USER,$CFG;
if (empty($cm->id)) {
debugging("Incorrect course module parameter!", DEBUG_DEVELOPER);
return false;
}
if (empty($userid)) {
$userid = $USER->id;
}
if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', context_module::instance($cm->id), $userid)) {
return false;
}
if ($CFG->enableavailability) {
require_once($CFG->libdir.'/conditionlib.php');
$ci=new condition_info($cm,CONDITION_MISSING_EXTRATABLE);
if(!$ci->is_available($cm->availableinfo,false,$userid) and
!has_capability('moodle/course:viewhiddenactivities',
context_module::instance($cm->id), $userid)) {
return false;
}
}
return groups_course_module_visible($cm, $userid);
}
/// LOG FUNCTIONS /////////////////////////////////////////////////////

View file

@ -2386,7 +2386,6 @@ function delete_course_module($id) {
// features are not turned on, in case they were turned on previously (these will be
// very quick on an empty table)
$DB->delete_records('course_modules_completion', array('coursemoduleid' => $cm->id));
$DB->delete_records('course_modules_availability', array('coursemoduleid'=> $cm->id));
$DB->delete_records('course_completion_criteria', array('moduleinstance' => $cm->id,
'criteriatype' => COMPLETION_CRITERIA_TYPE_ACTIVITY));
@ -4389,3 +4388,22 @@ function ajaxenabled(array $browsers = null) {
debugging('ajaxenabled() is deprecated - please update your code to assume it returns true.', DEBUG_DEVELOPER);
return true;
}
/**
* Determine whether a course module is visible within a course,
* this is different from instance_is_visible() - faster and visibility for user
*
* @global object
* @global object
* @uses DEBUG_DEVELOPER
* @uses CONTEXT_MODULE
* @param object $cm object
* @param int $userid empty means current user
* @return bool Success
* @deprecated Since Moodle 2.7
*/
function coursemodule_visible_for_user($cm, $userid=0) {
debugging('coursemodule_visible_for_user() deprecated since Moodle 2.7. ' .
'Replace with \core_availability\info_module::is_user_visible().');
return \core_availability\info_module::is_user_visible($cm, $userid, false);
}

View file

@ -99,9 +99,10 @@ class course_modinfo {
private $instances;
/**
* Groups that the current user belongs to. This value is usually not available (set to null)
* unless the course has activities set to groupmembersonly. When set, it is an array of
* grouping id => array of group id => group id. Includes grouping id 0 for 'all groups'.
* Groups that the current user belongs to. This value is calculated on first
* request to the property or function.
* When set, it is an array of grouping id => array of group id => group id.
* Includes grouping id 0 for 'all groups'.
* @var int[][]
*/
private $groups;
@ -562,7 +563,7 @@ class course_modinfo {
// Get section data
$sections = $DB->get_records('course_sections', array('course' => $course->id), 'section',
'section, id, course, name, summary, summaryformat, sequence, visible, ' .
'availablefrom, availableuntil, showavailability, groupingid');
'availability');
$compressedsections = array();
$formatoptionsdef = course_get_format($course)->section_format_options();
@ -658,7 +659,6 @@ class course_modinfo {
* - {@link cm_info::get_icon_url()}
* - {@link cm_info::$uservisible}
* - {@link cm_info::$available}
* - {@link cm_info::$showavailability}
* - {@link cm_info::$availableinfo}
* - plus any of the properties listed in Stage 3.
*
@ -723,12 +723,7 @@ class course_modinfo {
* @property-read int $completionview 1 if 'on view' completion is enabled, 0 otherwise - from course_modules table
* @property-read int $completionexpected Set to a unix time if completion of this activity is expected at a
* particular time, 0 if no time set - from course_modules table
* @property-read int $availablefrom Available date for this activity (0 if not set, or set to seconds since epoch; before this
* date, activity does not display to students) - from course_modules table
* @property-read int $availableuntil Available until date for this activity (0 if not set, or set to seconds since epoch; from
* this date, activity does not display to students) - from course_modules table
* @property-read int $showavailability When activity is unavailable, this field controls whether it is shown to students (0 =
* hide completely, 1 = show greyed out with information about when it will be available) -
* @property-read string $availability Availability information as JSON string or null if none -
* from course_modules table
* @property-read int $showdescription Controls whether the description of the activity displays on the course main page (in
* addition to anywhere it might display within the activity itself). 0 = do not show
@ -912,26 +907,10 @@ class cm_info implements IteratorAggregate {
private $completionexpected;
/**
* Available date for this activity (0 if not set, or set to seconds since epoch; before this
* date, activity does not display to students) - from course_modules table
* @var int
* Availability information as JSON string or null if none - from course_modules table
* @var string
*/
private $availablefrom;
/**
* Available until date for this activity (0 if not set, or set to seconds since epoch; from
* this date, activity does not display to students) - from course_modules table
* @var int
*/
private $availableuntil;
/**
* When activity is unavailable, this field controls whether it is shown to students (0 =
* hide completely, 1 = show greyed out with information about when it will be available) -
* from course_modules table
* @var int
*/
private $showavailability;
private $availability;
/**
* Controls whether the description of the activity displays on the course main page (in
@ -1095,10 +1074,11 @@ class cm_info implements IteratorAggregate {
'modplural' => 'get_module_type_name_plural',
'id' => false,
'added' => false,
'availability' => false,
'available' => 'get_available',
'availablefrom' => false,
'availablefrom' => 'get_deprecated_available_date',
'availableinfo' => 'get_available_info',
'availableuntil' => false,
'availableuntil' => 'get_deprecated_available_date',
'completion' => false,
'completionexpected' => false,
'completiongradeitemnumber' => false,
@ -1528,7 +1508,7 @@ class cm_info implements IteratorAggregate {
static $cmfields = array('id', 'course', 'module', 'instance', 'section', 'idnumber', 'added',
'score', 'indent', 'visible', 'visibleold', 'groupmode', 'groupingid', 'groupmembersonly',
'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected',
'availablefrom', 'availableuntil', 'showavailability', 'showdescription');
'showdescription', 'availability');
foreach ($cmfields as $key) {
$cmrecord->$key = $this->$key;
}
@ -1649,19 +1629,24 @@ class cm_info implements IteratorAggregate {
*
* When this is function is called, user-visible status is recalculated automatically.
*
* The $showavailability flag does not really do anything any more, but is retained
* for backward compatibility. Setting this to false will cause $availableinfo to
* be ignored.
*
* Note: May not be called from _cm_info_view (only _cm_info_dynamic).
* @param bool $available False if this item is not 'available'
* @param int $showavailability 0 = do not show this item at all if it's not available,
* 1 = show this item greyed out with the following message
* @param string $availableinfo Information about why this is not available which displays
* to those who have viewhiddenactivities, and to everyone if showavailability is set;
* note that this function replaces the existing data (if any)
* @param string $availableinfo Information about why this is not available, or
* empty string if not displaying
* @return void
*/
public function set_available($available, $showavailability=0, $availableinfo='') {
$this->check_not_view_only();
$this->available = $available;
$this->showavailability = $showavailability;
if (!$showavailability) {
$availableinfo = '';
}
$this->availableinfo = $availableinfo;
$this->update_user_visible();
}
@ -1730,9 +1715,7 @@ class cm_info implements IteratorAggregate {
? $mod->completionview : 0;
$this->completionexpected = isset($mod->completionexpected)
? $mod->completionexpected : 0;
$this->showavailability = isset($mod->showavailability) ? $mod->showavailability : 0;
$this->availablefrom = isset($mod->availablefrom) ? $mod->availablefrom : 0;
$this->availableuntil = isset($mod->availableuntil) ? $mod->availableuntil : 0;
$this->availability = isset($mod->availability) ? $mod->availability : null;
$this->conditionscompletion = isset($mod->conditionscompletion)
? $mod->conditionscompletion : array();
$this->conditionsgrade = isset($mod->conditionsgrade)
@ -1774,8 +1757,9 @@ class cm_info implements IteratorAggregate {
if (!empty($CFG->enableavailability)) {
require_once($CFG->libdir. '/conditionlib.php');
// Get availability information
$ci = new condition_info($this);
// 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,
@ -1820,12 +1804,32 @@ class cm_info implements IteratorAggregate {
}
/**
* Getter method for property $showavailability, ensures that dynamic data is retrieved
* Getter method for property $showavailability. Works by checking the
* availableinfo property to see if it's empty or not.
*
* @return int
* @deprecated Since Moodle 2.7
*/
private function get_show_availability() {
$this->obtain_dynamic_data();
return $this->showavailability;
debugging('$cm->showavailability property has been deprecated. You ' .
'can replace it by checking if $cm->availableinfo has content.',
DEBUG_DEVELOPER);
return ($this->get_available_info() !== '') ? 1 : 0;
}
/**
* Getter method for $availablefrom and $availableuntil. Just returns zero
* as these are no longer supported.
*
* @return int Zero
* @deprecated Since Moodle 2.7
*/
private function get_deprecated_available_date() {
debugging('$cm->availablefrom and $cm->availableuntil have been deprecated. This ' .
'information is no longer available as the system provides more complex ' .
'options (for example, there might be different dates for different users).',
DEBUG_DEVELOPER);
return 0;
}
/**
@ -1867,7 +1871,7 @@ class cm_info implements IteratorAggregate {
$this->uservisible = false;
// Ensure activity is completely hidden from the user.
$this->showavailability = 0;
$this->availableinfo = '';
}
}
@ -1918,12 +1922,23 @@ class cm_info implements IteratorAggregate {
}
/**
* Checks whether the module's conditional access settings mean that the user cannot see the activity at all
* Checks whether the module's conditional access settings mean that the
* user cannot see the activity at all
*
* This is deprecated because it is confusing (name sounds like it's about
* access restriction but it is actually about display), is not used
* anywhere, and is not necessary. Nobody (outside conditional libraries)
* should care what it is that restricted something.
*
* @return bool True if the user cannot see the module. False if the activity is either available or should be greyed out.
* @deprecated since 2.7
*/
public function is_user_access_restricted_by_conditional_access() {
global $CFG;
debugging('cm_info::is_user_access_restricted_by_conditional_access() ' .
'is deprecated; this function is not needed (use $cm->uservisible ' .
'and $cm->availableinfo) to decide whether it should be available ' .
'or appear)', DEBUG_DEVELOPER);
if (empty($CFG->enableavailability)) {
return false;
@ -1934,22 +1949,9 @@ class cm_info implements IteratorAggregate {
return null;
}
// If module will always be visible anyway (but greyed out), don't bother checking anything else
if ($this->get_show_availability() == CONDITION_STUDENTVIEW_SHOW) {
return false;
}
// Can the user see hidden modules?
if (has_capability('moodle/course:viewhiddenactivities', $this->get_context(), $userid)) {
return false;
}
// Is the module hidden due to unmet conditions?
if (!$this->get_available()) {
return true;
}
return false;
// Return false if user can access the activity, or if its availability
// info is set (= should be displayed even though not accessible).
return !$this->get_user_visible() && !$this->get_available_info();
}
/**
@ -2213,14 +2215,7 @@ class cached_cm_info {
* @property-read int $visible Section visibility (1 = visible) - from course_sections table
* @property-read string $summary Section summary text if specified - from course_sections table
* @property-read int $summaryformat Section summary text format (FORMAT_xx constant) - from course_sections table
* @property-read int $showavailability When section is unavailable, this field controls whether it is shown to students (0 =
* hide completely, 1 = show greyed out with information about when it will be available) -
* from course_sections table
* @property-read int $availablefrom Available date for this section (0 if not set, or set to seconds since epoch;
* before this date, section does not display to students) - from course_sections table
* @property-read int $availableuntil Available until date for this section (0 if not set, or set to seconds since epoch;
* from this date, section does not display to students) - from course_sections table
* @property-read int $groupingid If section is restricted to users of a particular grouping, this is its id (0 if not set) -
* @property-read string $availability Availability information as JSON string -
* from course_sections table
* @property-read array $conditionscompletion Availability conditions for this section based on the completion of
* course-modules (array from course-module id to required completion state
@ -2278,33 +2273,10 @@ class section_info implements IteratorAggregate {
private $_summaryformat;
/**
* When section is unavailable, this field controls whether it is shown to students (0 =
* hide completely, 1 = show greyed out with information about when it will be available) -
* from course_sections table
* @var int
* Availability information as JSON string - from course_sections table
* @var string
*/
private $_showavailability;
/**
* Available date for this section (0 if not set, or set to seconds since epoch; before this
* date, section does not display to students) - from course_sections table
* @var int
*/
private $_availablefrom;
/**
* Available until date for this section (0 if not set, or set to seconds since epoch; from
* this date, section does not display to students) - from course_sections table
* @var int
*/
private $_availableuntil;
/**
* If section is restricted to users of a particular grouping, this is its id
* (0 if not set) - from course_sections table
* @var int
*/
private $_groupingid;
private $_availability;
/**
* Availability conditions for this section based on the completion of
@ -2364,10 +2336,7 @@ class section_info implements IteratorAggregate {
'summary' => '',
'summaryformat' => '1', // FORMAT_HTML, but must be a string
'visible' => '1',
'showavailability' => '0',
'availablefrom' => '0',
'availableuntil' => '0',
'groupingid' => '0',
'availability' => null,
);
/**
@ -2518,15 +2487,10 @@ class section_info implements IteratorAggregate {
}
if (!empty($CFG->enableavailability)) {
require_once($CFG->libdir. '/conditionlib.php');
// Get availability information
$ci = new condition_info_section($this);
// Get availability information.
$ci = new \core_availability\info_section($this);
$this->_available = $ci->is_available($this->_availableinfo, true,
$userid, $this->modinfo);
if ($this->_availableinfo === '' && $this->_groupingid) {
// Still may have some extra text in availableinfo because of groupping.
// Set as undefined so the next call to get_availabeinfo() calculates it.
$this->_availableinfo = null;
}
} else {
$this->_available = true;
$this->_availableinfo = '';
@ -2607,6 +2571,62 @@ class section_info implements IteratorAggregate {
return $this->_uservisible;
}
/**
* Getter method for property $showavailability. Works by checking the
* availableinfo property to see if it's empty or not.
*
* @return int
* @deprecated Since Moodle 2.7
*/
private function get_showavailability() {
debugging('$section->showavailability property has been deprecated. You ' .
'can replace it by checking if $section->availableinfo has content.',
DEBUG_DEVELOPER);
return ($this->get_availableinfo() !== '') ? 1 : 0;
}
/**
* Getter method for $availablefrom. Just returns zero as no longer supported.
*
* @return int Zero
* @deprecated Since Moodle 2.7
*/
private function get_availablefrom() {
debugging('$section->availablefrom has been deprecated. This ' .
'information is no longer available as the system provides more complex ' .
'options (for example, there might be different dates for different users).',
DEBUG_DEVELOPER);
return 0;
}
/**
* Getter method for $availablefrom. Just returns zero as no longer supported.
*
* @return int Zero
* @deprecated Since Moodle 2.7
*/
private function get_availableuntil() {
debugging('$section->availableuntil has been deprecated. This ' .
'information is no longer available as the system provides more complex ' .
'options (for example, there might be different dates for different users).',
DEBUG_DEVELOPER);
return 0;
}
/**
* Getter method for $groupingid. Just returns zero as no longer supported.
*
* @return int Zero
* @deprecated Since Moodle 2.7
*/
private function get_groupingid() {
debugging('$section->groupingid has been deprecated. This ' .
'information is no longer available as the system provides more complex ' .
'options (for example, combining multiple groupings).',
DEBUG_DEVELOPER);
return 0;
}
/**
* Restores the course_sections.sequence value
*
@ -2646,18 +2666,6 @@ class section_info implements IteratorAggregate {
// Sequence stored implicity in modinfo $sections array
unset($section->sequence);
// Add availability data if turned on
if ($CFG->enableavailability) {
require_once($CFG->dirroot . '/lib/conditionlib.php');
condition_info_section::fill_availability_conditions($section);
if (count($section->conditionscompletion) == 0) {
unset($section->conditionscompletion);
}
if (count($section->conditionsgrade) == 0) {
unset($section->conditionsgrade);
}
}
// Remove default data
foreach (self::$sectioncachedefaults as $field => $value) {
// Exact compare as strings to avoid problems if some strings are set

View file

@ -5073,12 +5073,6 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
$DB->delete_records_select('course_modules_completion',
'coursemoduleid IN (SELECT id from {course_modules} WHERE course=?)',
array($courseid));
$DB->delete_records_select('course_modules_availability',
'coursemoduleid IN (SELECT id from {course_modules} WHERE course=?)',
array($courseid));
$DB->delete_records_select('course_modules_avail_fields',
'coursemoduleid IN (SELECT id from {course_modules} WHERE course=?)',
array($courseid));
// Remove course-module data.
$cms = $DB->get_records('course_modules', array('course' => $course->id));
@ -5188,13 +5182,7 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
}
$DB->update_record('course', $oldcourse);
// Delete course sections and availability options.
$DB->delete_records_select('course_sections_availability',
'coursesectionid IN (SELECT id from {course_sections} WHERE course=?)',
array($course->id));
$DB->delete_records_select('course_sections_avail_fields',
'coursesectionid IN (SELECT id from {course_sections} WHERE course=?)',
array($course->id));
// Delete course sections.
$DB->delete_records('course_sections', array('course' => $course->id));
// Delete legacy, section and any other course files.

View file

@ -176,7 +176,7 @@ abstract class testing_module_generator extends component_generator_base {
$easymergefields = array('section', 'added', 'score', 'indent',
'visible', 'visibleold', 'groupmode', 'groupingid', 'groupmembersonly',
'completion', 'completiongradeitemnumber', 'completionview', 'completionexpected',
'availablefrom', 'availableuntil', 'showavailability', 'showdescription');
'availability', 'showdescription');
foreach ($easymergefields as $key) {
if (isset($options[$key])) {
$moduleinfo->$key = $options[$key];
@ -191,9 +191,7 @@ abstract class testing_module_generator extends component_generator_base {
'groupmode' => 0,
'groupingid' => 0,
'groupmembersonly' => 0,
'showavailability' => 0,
'availablefrom' => 0,
'availableuntil' => 0,
'availability' => null,
'completion' => 0,
'completionview' => 0,
'completionexpected' => 0,

View file

@ -213,57 +213,10 @@ class core_test_generator_testcase extends advanced_testcase {
// We need id of the grading item for the second module to create availability dependency in the 3rd module.
$gradingitem = grade_item::fetch(array('courseid'=>$course->id, 'itemtype'=>'mod', 'itemmodule' => 'assign', 'iteminstance' => $m3->id));
// Now prepare options to create the 4th module which availability depends on other modules.
// Following options available if $CFG->enableavailability is set:
// Now prepare option to create the 4th module with an availability condition.
$optionsavailability = array(
'showavailability' => 1,
'availablefrom' => time() - WEEKSECS,
'availableuntil' => time() + WEEKSECS,
'conditiongradegroup' => array(
array(
'conditiongradeitemid' => $gradingitem->id,
'conditiongrademin' => 20,
'conditiongrademax' => 80,
)
),
'conditionfieldgroup' => array(
array(
'conditionfield' => 'address',
'conditionfieldoperator' => 'contains',
'conditionfieldvalue' => 'street',
)
),
'conditioncompletiongroup' => array(
array(
'conditionsourcecmid' => $m2->cmid,
'conditionrequiredcompletion' => 1
),
array(
'conditionsourcecmid' => $m3->cmid,
'conditionrequiredcompletion' => 1
)
)
);
// The same data for assertion (different format).
$optionsavailabilityassertion = array(
'conditionsgrade' => array(
$gradingitem->id => (object)array(
'min' => 20,
'max' => 80,
'name' => $gradingitem->itemname
)
),
'conditionsfield' => array(
'address' => (object)array(
'fieldname' => 'address',
'operator' => 'contains',
'value' => 'street'
)
),
'conditionscompletion' => array(
$m2->cmid => 1,
$m3->cmid => 1
)
'availability' => '{"op":"&","showc":[true],"c":[' .
'{"type":"date","d":">=","t":' . (time() - WEEKSECS) . '}]}',
);
// Create module with conditional availability.
@ -304,12 +257,7 @@ class core_test_generator_testcase extends advanced_testcase {
$this->assertEquals($featuregrade['gradecat'], $gradingitem->categoryid);
$cm4 = $modinfo->cms[$m4->cmid];
$this->assertEquals($optionsavailability['showavailability'], $cm4->showavailability);
$this->assertEquals($optionsavailability['availablefrom'], $cm4->availablefrom);
$this->assertEquals($optionsavailability['availableuntil'], $cm4->availableuntil);
$this->assertEquals($optionsavailabilityassertion['conditionsgrade'], $cm4->conditionsgrade);
$this->assertEquals($optionsavailabilityassertion['conditionsfield'], $cm4->conditionsfield);
$this->assertEquals($optionsavailabilityassertion['conditionscompletion'], $cm4->conditionscompletion);
$this->assertEquals($optionsavailability['availability'], $cm4->availability);
}
public function test_create_block() {

View file

@ -58,27 +58,17 @@ class core_modinfolib_testcase extends advanced_testcase {
array('course' => $course->id),
array('completion' => 1));
// Generate the module and add availability conditions.
$conditionscompletion = array($prereqforum->cmid => COMPLETION_COMPLETE);
$conditionsgrade = array(666 => (object)array('min' => 0.4, 'max' => null, 'name' => '!missing'));
$conditionsfield = array('email' => (object)array(
'fieldname' => 'email',
'operator' => 'contains',
'value' => 'test'
));
$sectiondb = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 2));
$ci = new condition_info_section((object)array('id' => $sectiondb->id), CONDITION_MISSING_EVERYTHING);
foreach ($conditionscompletion as $cmid => $requiredcompletion) {
$ci->add_completion_condition($cmid, $requiredcompletion);
}
foreach ($conditionsgrade as $gradeid => $conditiongrade) {
$ci->add_grade_condition($gradeid, $conditiongrade->min, $conditiongrade->max, true);
}
foreach ($conditionsfield as $conditionfield) {
$ci->add_user_field_condition($conditionfield->fieldname, $conditionfield->operator, $conditionfield->value);
}
// Direct calls to condition_info_section methods do not reset the course cache. Do it manually.
// Add availability conditions.
$availability = '{"op":"&","showc":[true,true,true],"c":[' .
'{"type":"completion","cm":' . $prereqforum->cmid . ',"e":"' .
COMPLETION_COMPLETE . '"},' .
'{"type":"grade","id":666,"min":0.4},' .
'{"type":"profile","op":"contains","sf":"email","v":"test"}' .
']}';
$DB->set_field('course_sections', 'availability', $availability,
array('course' => $course->id, 'section' => 2));
rebuild_course_cache($course->id, true);
$sectiondb = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 2));
// Create and enrol a student.
$studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
@ -100,14 +90,8 @@ class core_modinfolib_testcase extends advanced_testcase {
$this->assertEquals($sectiondb->visible, $si->visible);
$this->assertEquals($sectiondb->summary, $si->summary);
$this->assertEquals($sectiondb->summaryformat, $si->summaryformat);
$this->assertEquals($sectiondb->showavailability, $si->showavailability);
$this->assertEquals($sectiondb->availablefrom, $si->availablefrom);
$this->assertEquals($sectiondb->availableuntil, $si->availableuntil);
$this->assertEquals($sectiondb->groupingid, $si->groupingid);
$this->assertEquals($sectiondb->sequence, $si->sequence); // Since this section does not contain invalid modules.
$this->assertEquals($conditionscompletion, $si->conditionscompletion);
$this->assertEquals($conditionsgrade, $si->conditionsgrade);
$this->assertEquals($conditionsfield, $si->conditionsfield);
$this->assertEquals($availability, $si->availability);
// Dynamic fields, just test that they can be retrieved (must be carefully tested in each activity type).
$this->assertEquals(0, $si->available);
@ -142,31 +126,18 @@ class core_modinfolib_testcase extends advanced_testcase {
array('course' => $course->id),
array('completion' => 1));
// Generate the module and add availability conditions.
$conditionscompletion = array($prereqforum->cmid => COMPLETION_COMPLETE);
$conditionsgrade = array(666 => (object)array('min' => 0.4, 'max' => null, 'name' => '!missing'));
$conditionsfield = array('email' => (object)array(
'fieldname' => 'email',
'operator' => 'contains',
'value' => 'test'
));
// Generate module and add availability conditions.
$availability = '{"op":"&","showc":[true,true,true],"c":[' .
'{"type":"completion","cm":' . $prereqforum->cmid . ',"e":"' .
COMPLETION_COMPLETE . '"},' .
'{"type":"grade","id":666,"min":0.4},' .
'{"type":"profile","op":"contains","sf":"email","v":"test"}' .
']}';
$assign = $this->getDataGenerator()->create_module('assign',
array('course' => $course->id),
array('idnumber' => 123,
'groupmode' => VISIBLEGROUPS,
'availablefrom' => time() + 3600,
'availableuntil' => time() + 5*3600));
$ci = new condition_info((object)array('id' => $assign->cmid), CONDITION_MISSING_EVERYTHING);
foreach ($conditionscompletion as $cmid => $requiredcompletion) {
$ci->add_completion_condition($cmid, $requiredcompletion);
}
foreach ($conditionsgrade as $gradeid => $conditiongrade) {
$ci->add_grade_condition($gradeid, $conditiongrade->min, $conditiongrade->max, true);
}
foreach ($conditionsfield as $conditionfield) {
$ci->add_user_field_condition($conditionfield->fieldname, $conditionfield->operator, $conditionfield->value);
}
// Direct access to condition_info functions does not reset course cache, do it manually.
'availability' => $availability));
rebuild_course_cache($course->id, true);
// Retrieve all related records from DB.
@ -216,9 +187,6 @@ class core_modinfolib_testcase extends advanced_testcase {
$this->assertEquals($moduledb->completiongradeitemnumber, $cm->completiongradeitemnumber);
$this->assertEquals($moduledb->completionview, $cm->completionview);
$this->assertEquals($moduledb->completionexpected, $cm->completionexpected);
$this->assertEquals($moduledb->availablefrom, $cm->availablefrom);
$this->assertEquals($moduledb->availableuntil, $cm->availableuntil);
$this->assertEquals($moduledb->showavailability, $cm->showavailability);
$this->assertEquals($moduledb->showdescription, $cm->showdescription);
$this->assertEquals(null, $cm->extra); // Deprecated field. Used in module types that don't return cached_cm_info.
$this->assertEquals($cachedcminfo->icon, $cm->icon);
@ -228,9 +196,7 @@ class core_modinfolib_testcase extends advanced_testcase {
$this->assertEquals($cachedcminfo->name, $cm->name);
$this->assertEquals($sectiondb->section, $cm->sectionnum);
$this->assertEquals($moduledb->section, $cm->section);
$this->assertEquals($conditionscompletion, $cm->conditionscompletion);
$this->assertEquals($conditionsgrade, $cm->conditionsgrade);
$this->assertEquals($conditionsfield, $cm->conditionsfield);
$this->assertEquals($availability, $cm->availability);
$this->assertEquals(context_module::instance($moduledb->id), $cm->context);
$this->assertEquals($modnamessingular['assign'], $cm->modfullname);
$this->assertEquals($modnamesplural['assign'], $cm->modplural);
@ -553,12 +519,14 @@ class core_modinfolib_testcase extends advanced_testcase {
$course = $this->getDataGenerator()->create_course();
// 1. Create an activity that is currently unavailable and hidden entirely (for students).
$assign1 = $this->getDataGenerator()->create_module('assign', array('course'=>$course->id),
array('availablefrom' => time() + 10000, 'showavailability' => CONDITION_STUDENTVIEW_HIDE));
array('availability' => '{"op":"|","show":false,"c":[' .
'{"type":"date","d":">=","t":' . (time() + 10000) . '}]}'));
// 2. Create an activity that is currently available.
$assign2 = $this->getDataGenerator()->create_module('assign', array('course'=>$course->id));
// 3. Create an activity that is currently unavailable and set to be greyed out.
$assign3 = $this->getDataGenerator()->create_module('assign', array('course'=>$course->id),
array('availablefrom' => time() + 10000, 'showavailability' => CONDITION_STUDENTVIEW_SHOW));
array('availability' => '{"op":"|","show":true,"c":[' .
'{"type":"date","d":">=","t":' . (time() + 10000) . '}]}'));
// Set up a teacher.
$coursecontext = context_course::instance($course->id);
@ -568,39 +536,52 @@ class core_modinfolib_testcase extends advanced_testcase {
// If conditional availability is disabled the activity will always be unrestricted.
$CFG->enableavailability = false;
$cm_info = get_fast_modinfo($course)->instances['assign'][$assign1->id];
$this->assertFalse($cm_info->is_user_access_restricted_by_conditional_access());
$cm = get_fast_modinfo($course)->instances['assign'][$assign1->id];
$this->assertTrue($cm->uservisible);
// Test deprecated function.
$this->assertFalse($cm->is_user_access_restricted_by_conditional_access());
$this->assertEquals(1, count(phpunit_util::get_debugging_messages()));
phpunit_util::reset_debugging();
// Turn on conditional availability and reset the get_fast_modinfo cache.
$CFG->enableavailability = true;
get_fast_modinfo($course, 0, true);
// The unavailable, hidden entirely activity should now be restricted.
$cm_info = get_fast_modinfo($course)->instances['assign'][$assign1->id];
$this->assertFalse($cm_info->available);
$this->assertEquals(CONDITION_STUDENTVIEW_HIDE, $cm_info->showavailability);
$this->assertTrue($cm_info->is_user_access_restricted_by_conditional_access());
$cm = get_fast_modinfo($course)->instances['assign'][$assign1->id];
$this->assertFalse($cm->uservisible);
$this->assertFalse($cm->available);
$this->assertEquals('', $cm->availableinfo);
// Test deprecated function.
$this->assertTrue($cm->is_user_access_restricted_by_conditional_access());
$this->assertEquals(1, count(phpunit_util::get_debugging_messages()));
phpunit_util::reset_debugging();
// If the activity is available it should not be restricted.
$cm_info = get_fast_modinfo($course)->instances['assign'][$assign2->id];
$this->assertTrue($cm_info->available);
$this->assertFalse($cm_info->is_user_access_restricted_by_conditional_access());
$cm = get_fast_modinfo($course)->instances['assign'][$assign2->id];
$this->assertTrue($cm->uservisible);
$this->assertTrue($cm->available);
// If the activity is unavailable and set to be greyed out it should not be restricted.
$cm_info = get_fast_modinfo($course)->instances['assign'][$assign3->id];
$this->assertFalse($cm_info->available);
$this->assertEquals(CONDITION_STUDENTVIEW_SHOW, $cm_info->showavailability);
$this->assertFalse($cm_info->is_user_access_restricted_by_conditional_access());
$cm = get_fast_modinfo($course)->instances['assign'][$assign3->id];
$this->assertFalse($cm->uservisible);
$this->assertFalse($cm->available);
$this->assertNotEquals('', (string)$cm->availableinfo);
// Test deprecated function (weird case, it actually checks visibility).
$this->assertFalse($cm->is_user_access_restricted_by_conditional_access());
$this->assertEquals(1, count(phpunit_util::get_debugging_messages()));
phpunit_util::reset_debugging();
// If the activity is unavailable and set to be hidden entirely its restricted unless user has 'moodle/course:viewhiddenactivities'.
// Switch to a teacher and reload the context info.
$this->setUser($teacher);
$cm_info = get_fast_modinfo($course)->instances['assign'][$assign1->id];
$this->assertFalse($cm_info->available);
$this->assertEquals(CONDITION_STUDENTVIEW_HIDE, $cm_info->showavailability);
$this->assertTrue(has_capability('moodle/course:viewhiddenactivities', $coursecontext));
$this->assertFalse($cm_info->is_user_access_restricted_by_conditional_access());
$cm = get_fast_modinfo($course)->instances['assign'][$assign1->id];
$this->assertTrue($cm->uservisible);
$this->assertFalse($cm->available);
}
public function test_is_user_access_restricted_by_capability() {
@ -718,10 +699,12 @@ class core_modinfolib_testcase extends advanced_testcase {
'idnumber' => '12345',
'showdescription' => true
));
// Pick a small valid availability value to use.
$availabilityvalue = '{"op":"|","show":true,"c":[{"type":"date","d":">=","t":4}]}';
$mods[2] = $this->getDataGenerator()->create_module('book',
array('course' => $course->id,
'indent' => 5,
'showavailability' => true,
'availability' => $availabilityvalue,
'showdescription' => false,
'completion' => true,
'completionview' => true,
@ -730,10 +713,8 @@ class core_modinfolib_testcase extends advanced_testcase {
$mods[3] = $this->getDataGenerator()->create_module('forum',
array('course' => $course->id,
'visible' => 0,
'availablefrom' => time() - 1000,
'availableto' => time() + 1000,
'groupmode' => 1,
'showavailability' => false));
'availability' => null));
$mods[4] = $this->getDataGenerator()->create_module('forum',
array('course' => $course->id,
'groupmembersonly' => true,
@ -805,4 +786,120 @@ class core_modinfolib_testcase extends advanced_testcase {
$this->assertEquals($cm2, $cminfo->get_course_module_record(true));
}
/**
* Tests the availability property that has been added to course modules
* and sections (just to see that it is correctly saved and accessed).
*/
public function test_availability_property() {
global $DB, $CFG;
$this->resetAfterTest();
// Create a course with two modules and three sections.
$course = $this->getDataGenerator()->create_course(
array('format' => 'topics', 'numsections' => 3),
array('createsections' => true));
$forum = $this->getDataGenerator()->create_module('forum',
array('course' => $course->id));
$forum2 = $this->getDataGenerator()->create_module('forum',
array('course' => $course->id));
// Get modinfo. Check that availability is null for both cm and sections.
$modinfo = get_fast_modinfo($course->id);
$cm = $modinfo->get_cm($forum->cmid);
$this->assertNull($cm->availability);
$section = $modinfo->get_section_info(1, MUST_EXIST);
$this->assertNull($section->availability);
// Update availability for cm and section in database.
$DB->set_field('course_modules', 'availability', '{}', array('id' => $cm->id));
$DB->set_field('course_sections', 'availability', '{}', array('id' => $section->id));
// Clear cache and get modinfo again.
rebuild_course_cache($course->id, true);
get_fast_modinfo(0, 0, true);
$modinfo = get_fast_modinfo($course->id);
// Check values that were changed.
$cm = $modinfo->get_cm($forum->cmid);
$this->assertEquals('{}', $cm->availability);
$section = $modinfo->get_section_info(1, MUST_EXIST);
$this->assertEquals('{}', $section->availability);
// Check other values are still null.
$cm = $modinfo->get_cm($forum2->cmid);
$this->assertNull($cm->availability);
$section = $modinfo->get_section_info(2, MUST_EXIST);
$this->assertNull($section->availability);
}
/**
* Some properties have been deprecated from both the section and module
* classes. This checks they still work (and show warnings).
*/
public function test_availability_deprecations() {
global $CFG, $DB;
$this->resetAfterTest();
$CFG->enableavailability = true;
// Create a course with two modules. The modules are not available to
// users. One of them is set to show this information, the other is not.
// Same setup for sections.
$generator = $this->getDataGenerator();
$course = $this->getDataGenerator()->create_course(
array('format' => 'topics', 'numsections' => 2),
array('createsections' => true));
$show = '{"op":"|","show":true,"c":[{"type":"date","d":"<","t":1395857332}]}';
$noshow = '{"op":"|","show":false,"c":[{"type":"date","d":"<","t":1395857332}]}';
$forum1 = $generator->create_module('forum',
array('course' => $course->id, 'availability' => $show));
$forum2 = $generator->create_module('forum',
array('course' => $course->id, 'availability' => $noshow));
$DB->set_field('course_sections', 'availability',
$show, array('course' => $course->id, 'section' => 1));
$DB->set_field('course_sections', 'availability',
$noshow, array('course' => $course->id, 'section' => 2));
// Create a user without special permissions.
$user = $generator->create_user();
$generator->enrol_user($user->id, $course->id);
// Get modinfo and cm objects.
$modinfo = get_fast_modinfo($course, $user->id);
$cm1 = $modinfo->get_cm($forum1->cmid);
$cm2 = $modinfo->get_cm($forum2->cmid);
// Check the showavailability property.
$this->assertEquals(1, $cm1->showavailability);
$this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
$this->assertEquals(0, $cm2->showavailability);
$this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
// Check the dates (these always return 0 now).
$this->assertEquals(0, $cm1->availablefrom);
$this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
$this->assertEquals(0, $cm1->availableuntil);
$this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
// Get section objects.
$section1 = $modinfo->get_section_info(1);
$section2 = $modinfo->get_section_info(2);
// Check showavailability.
$this->assertEquals(1, $section1->showavailability);
$this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
$this->assertEquals(0, $section2->showavailability);
$this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
// Check dates (zero).
$this->assertEquals(0, $section1->availablefrom);
$this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
$this->assertEquals(0, $section1->availableuntil);
$this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
// Check groupingid (zero).
$this->assertEquals(0, $section1->groupingid);
$this->assertDebuggingCalled(null, DEBUG_DEVELOPER);
}
}

View file

@ -22,11 +22,32 @@ DEPRECATIONS:
* mod_feedback\event\instances_list_viewed has been deprecated. Please use mod_feedback\event\course_module_instance_list_viewed instead.
* mod_page\event\instances_list_viewed has been deprecated. Please use mod_page\event\course_module_instance_list_viewed instead.
* The constants FRONTPAGECOURSELIST, FRONTPAGETOPICONLY & FRONTPAGECOURSELIMIT have been removed.
* Conditional availability API has moved and changed. The condition_info class is
replaced by \core_availability\info_module, and condition_info_section by
\core_availability\info_section. (Code that uses the old classes will generally
still work.)
* coursemodule_visible_for_user() has been deprecated but still works - replaced
by a new static function \core_availability\info_module::is_user_visible()
* cm_info::is_user_access_restricted_by_conditional_access has been deprecated
but still works (it has never done what its name suggests, and is
unnecessary).
* cm_info and section_info property showavailability has been deprecated, but
still works (with the caveat that this information is now per-user).
* cm_info and section_info properties availablefrom and availableuntil have been
deprecated and always return zero (underlying data doesn't have these values).
* section_info property groupingid has been deprecated and always returns zero,
same deal.
* Various cm_info methods have been deprecated in favour of their read-only properties (get_url(), get_content(), get_extra_classes(),
get_on_click(), get_custom_data(), get_after_link, get_after_edit_icons)
* The ajaxenabled function has been deprecated and always returns true. All code should be fully functional in Javascript.
* count_login_failures() has been deprecated, use user_count_login_failures() instead. Refer MDL-42891 for details.
Conditional availability (activities and sections):
* New conditional availability API in /availability, including new availability
condition plugins in /availability/condition. The new API is very similar with
regard to checking availability, but any code that modifies availability settings
for an activity or section is likely to need substantial changes.
YUI:
* The lightbox attribute for moodle-core-notification-dialogue has been
deprecated and replaced by the modal attribute. This was actually