mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
MDL-15499: Conditional availability of activities
This commit is contained in:
parent
5373887a7c
commit
82bd6a5ea9
@ -14,11 +14,6 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$item->set_updatedcallback('reset_text_filters_cache');
|
||||
$temp->add($item);
|
||||
|
||||
// Completion system
|
||||
require_once($CFG->libdir.'/completionlib.php');
|
||||
$temp->add(new admin_setting_configcheckbox('enablecompletion', get_string('enablecompletion','completion'), get_string('configenablecompletion','completion'), COMPLETION_DISABLED));
|
||||
$temp->add(new admin_setting_pickroles('progresstrackedroles', get_string('progresstrackedroles','completion'), get_string('configprogresstrackedroles', 'completion'), array('moodle/legacy:student')));
|
||||
|
||||
$ADMIN->add('experimental', $temp);
|
||||
|
||||
// DB transfer related pages
|
||||
|
@ -29,4 +29,15 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$options = array('off'=>get_string('off', 'mnet'), 'strict'=>get_string('on', 'mnet'));
|
||||
$optionalsubsystems->add(new admin_setting_configselect('mnet_dispatcher_mode', get_string('net', 'mnet'), get_string('configmnet', 'mnet'), 'off', $options));
|
||||
|
||||
// Conditional activities: completion and availability
|
||||
$optionalsubsystems->add(new admin_setting_configcheckbox('enablecompletion',
|
||||
get_string('enablecompletion','completion'),
|
||||
get_string('configenablecompletion','completion'), 0));
|
||||
$optionalsubsystems->add(new admin_setting_pickroles('progresstrackedroles',
|
||||
get_string('progresstrackedroles','completion'),
|
||||
get_string('configprogresstrackedroles', 'completion'),
|
||||
array('moodle/legacy:student')));
|
||||
$optionalsubsystems->add(new admin_setting_configcheckbox('enableavailability',
|
||||
get_string('enableavailability','condition'),
|
||||
get_string('configenableavailability','condition'), 0));
|
||||
}
|
||||
|
@ -1227,6 +1227,10 @@
|
||||
fwrite ($bf,full_tag("COMPLETIONGRADEITEMNUMBER",6,false,$course_module->completiongradeitemnumber));
|
||||
fwrite ($bf,full_tag("COMPLETIONVIEW",6,false,$course_module->completionview));
|
||||
fwrite ($bf,full_tag("COMPLETIONEXPECTED",6,false,$course_module->completionexpected));
|
||||
fwrite ($bf,full_tag("AVAILABLEFROM",6,false,$course_module->availablefrom));
|
||||
fwrite ($bf,full_tag("AVAILABLEUNTIL",6,false,$course_module->availableuntil));
|
||||
fwrite ($bf,full_tag("SHOWAVAILABILITY",6,false,$course_module->showavailability));
|
||||
|
||||
// get all the role_capabilities overrides in this mod
|
||||
write_role_overrides_xml($bf, $context, 6);
|
||||
/// write role_assign code here
|
||||
@ -1254,6 +1258,27 @@
|
||||
fwrite ($bf,end_tag("COMPLETIONDATA",6,true));
|
||||
}
|
||||
|
||||
// Write availability data if enabled
|
||||
require_once($CFG->libdir.'/conditionlib.php');
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
fwrite ($bf,start_tag("AVAILABILITYDATA",6,true));
|
||||
// Get all availability restrictions for this activity
|
||||
$data=$DB->get_records('course_modules_availability',
|
||||
array('coursemoduleid'=>$course_module->id));
|
||||
$data=$data ? $data : array();
|
||||
foreach($data as $availability) {
|
||||
// Write availability record
|
||||
fwrite ($bf,start_tag("AVAILABILITY",7,true));
|
||||
fwrite ($bf,full_tag("SOURCECMID",8,false,$availability->sourcecmid));
|
||||
fwrite ($bf,full_tag("REQUIREDCOMPLETION",8,false,$availability->requiredcompletion));
|
||||
fwrite ($bf,full_tag("GRADEITEMID",8,false,$availability->gradeitemid));
|
||||
fwrite ($bf,full_tag("GRADEMIN",8,false,$availability->grademin));
|
||||
fwrite ($bf,full_tag("GRADEMAX",8,false,$availability->grademax));
|
||||
fwrite ($bf,end_tag("AVAILABILITY",7,true));
|
||||
}
|
||||
fwrite ($bf,end_tag("AVAILABILITYDATA",6,true));
|
||||
}
|
||||
|
||||
fwrite ($bf,end_tag("MOD",5,true));
|
||||
}
|
||||
//check for next
|
||||
|
@ -1127,6 +1127,10 @@ define('RESTORE_GROUPS_GROUPINGS', 3);
|
||||
$course_module->completionview=$mod->completionview;
|
||||
$course_module->completionexpected=$mod->completionexpected;
|
||||
|
||||
$course_module->availablefrom=$mod->availablefrom+$restore->course_startdateoffset;
|
||||
$course_module->availableuntil=$mod->availableuntil+$restore->course_startdateoffset;
|
||||
$course_module->showavailability=$mod->showavailability;
|
||||
|
||||
$newidmod = $DB->insert_record("course_modules", $course_module);
|
||||
if ($newidmod) {
|
||||
//save old and new module id
|
||||
@ -1221,6 +1225,61 @@ define('RESTORE_GROUPS_GROUPINGS', 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Store availability information
|
||||
if($status && !empty($info->availabilitydata) && count($info->availabilitydata)>0) {
|
||||
|
||||
foreach($info->availabilitydata as $data) {
|
||||
// Convert cmid
|
||||
$newcmid=backup_getid($restore->backup_unique_code, 'course_modules', $data->coursemoduleid);
|
||||
if($newcmid) {
|
||||
$data->coursemoduleid=$newcmid->new_id;
|
||||
} else {
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo "<p>Can't find new ID for cm $data->coursemoduleid, ignoring availability condition.</p>";
|
||||
}
|
||||
$status=false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert source cmid
|
||||
if($data->sourcecmid) {
|
||||
$newcmid=backup_getid($restore->backup_unique_code, 'course_modules', $data->sourcecmid);
|
||||
if($newcmid) {
|
||||
$data->sourcecmid=$newcmid->new_id;
|
||||
} else {
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo "<p>Can't find new ID for source cm $data->sourcecmid, ignoring availability condition.</p>";
|
||||
}
|
||||
$status=false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert grade id
|
||||
if($data->gradeitemid) {
|
||||
$newgradeid=backup_getid($restore->backup_unique_code,
|
||||
'grade_items',$data->gradeitemid);
|
||||
if($newgradeid) {
|
||||
$data->gradeitemid=$newgradeid->new_id;
|
||||
} else {
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo "<p>Can't find new ID for grade item $data->gradeitemid, ignoring availability condition.</p>";
|
||||
}
|
||||
$status=false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add record
|
||||
if(!$DB->insert_record('course_modules_availability',$data)) {
|
||||
if (!defined('RESTORE_SILENTLY')) {
|
||||
echo "<p>Failed to insert availability data record.</p>";
|
||||
}
|
||||
$status=false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$status = false;
|
||||
}
|
||||
@ -5618,6 +5677,12 @@ define('RESTORE_GROUPS_GROUPINGS', 3);
|
||||
isset($this->info->tempmod->completionview) ? $this->info->tempmod->completionview : 0;
|
||||
$this->info->tempsection->mods[$this->info->tempmod->id]->completionexpected =
|
||||
isset($this->info->tempmod->completionexpected) ? $this->info->tempmod->completionexpected : 0;
|
||||
$this->info->tempsection->mods[$this->info->tempmod->id]->availablefrom =
|
||||
isset($this->info->tempmod->availablefrom) ? $this->info->tempmod->availablefrom : 0;
|
||||
$this->info->tempsection->mods[$this->info->tempmod->id]->availableuntil =
|
||||
isset($this->info->tempmod->availableuntil) ? $this->info->tempmod->availableuntil : 0;
|
||||
$this->info->tempsection->mods[$this->info->tempmod->id]->showavailability =
|
||||
isset($this->info->tempmod->showavailability) ? $this->info->tempmod->showavailability : 0;
|
||||
|
||||
unset($this->info->tempmod);
|
||||
}
|
||||
@ -5669,6 +5734,15 @@ define('RESTORE_GROUPS_GROUPINGS', 3);
|
||||
case "COMPLETIONEXPECTED":
|
||||
$this->info->tempmod->completionexpected = $this->getContents();
|
||||
break;
|
||||
case "AVAILABLEFROM":
|
||||
$this->info->tempmod->availablefrom = $this->getContents();
|
||||
break;
|
||||
case "AVAILABLEUNTIL":
|
||||
$this->info->tempmod->availableuntil = $this->getContents();
|
||||
break;
|
||||
case "SHOWAVAILABILITY":
|
||||
$this->info->tempmod->showavailability = $this->getContents();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -5794,6 +5868,40 @@ define('RESTORE_GROUPS_GROUPINGS', 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->tree[7]) && $this->tree[7] == "AVAILABILITYDATA") {
|
||||
if($this->level == 8) {
|
||||
switch($tagName) {
|
||||
case 'AVAILABILITY':
|
||||
// Got all data to make completion entry...
|
||||
$this->info->tempavailability->coursemoduleid=$this->info->tempmod->id;
|
||||
$this->info->availabilitydata[]=$this->info->tempavailability;
|
||||
unset($this->info->tempavailability);
|
||||
$this->info->tempavailability=new stdClass;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($this->level == 9) {
|
||||
switch($tagName) {
|
||||
case 'SOURCECMID' :
|
||||
$this->info->tempavailability->sourcecmid=$this->getContents();
|
||||
break;
|
||||
case 'REQUIREDCOMPLETION' :
|
||||
$this->info->tempavailability->requiredcompletion=$this->getContents();
|
||||
break;
|
||||
case 'GRADEITEMID' :
|
||||
$this->info->tempavailability->gradeitemid=$this->getContents();
|
||||
break;
|
||||
case 'GRADEMIN' :
|
||||
$this->info->tempavailability->grademin=$this->getContents();
|
||||
break;
|
||||
case 'GRADEMAX' :
|
||||
$this->info->tempavailability->grademax=$this->getContents();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Stop parsing if todo = SECTIONS and tagName = SECTIONS (en of the tag, of course)
|
||||
|
121
course/lib.php
121
course/lib.php
@ -982,6 +982,9 @@ function get_array_of_activities($courseid) {
|
||||
// groupmembersonly - is this instance visible to group members only
|
||||
// extra - contains extra string to include in any link
|
||||
global $CFG, $DB;
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
require_once($CFG->libdir.'/conditionlib.php');
|
||||
}
|
||||
|
||||
$mod = array();
|
||||
|
||||
@ -1005,7 +1008,17 @@ function get_array_of_activities($courseid) {
|
||||
$mod[$seq]->groupmode = $rawmods[$seq]->groupmode;
|
||||
$mod[$seq]->groupingid = $rawmods[$seq]->groupingid;
|
||||
$mod[$seq]->groupmembersonly = $rawmods[$seq]->groupmembersonly;
|
||||
$mod[$seq]->indent = $rawmods[$seq]->indent;
|
||||
$mod[$seq]->completion = $rawmods[$seq]->completion;
|
||||
$mod[$seq]->extra = "";
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
condition_info::fill_availability_conditions($rawmods[$seq]);
|
||||
$mod[$seq]->availablefrom = $rawmods[$seq]->availablefrom;
|
||||
$mod[$seq]->availableuntil = $rawmods[$seq]->availableuntil;
|
||||
$mod[$seq]->showavailability = $rawmods[$seq]->showavailability;
|
||||
$mod[$seq]->conditionscompletion = $rawmods[$seq]->conditionscompletion;
|
||||
$mod[$seq]->conditionsgrade = $rawmods[$seq]->conditionsgrade;
|
||||
}
|
||||
|
||||
$modname = $mod[$seq]->mod;
|
||||
$functionname = $modname."_get_coursemodule_info";
|
||||
@ -1048,6 +1061,9 @@ function get_array_of_activities($courseid) {
|
||||
*/
|
||||
function &get_fast_modinfo(&$course, $userid=0) {
|
||||
global $CFG, $USER, $DB;
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
require_once($CFG->libdir.'/conditionlib.php');
|
||||
}
|
||||
|
||||
static $cache = array();
|
||||
|
||||
@ -1132,9 +1148,27 @@ function &get_fast_modinfo(&$course, $userid=0) {
|
||||
$cm->groupmode = $mod->groupmode;
|
||||
$cm->groupingid = $mod->groupingid;
|
||||
$cm->groupmembersonly = $mod->groupmembersonly;
|
||||
$cm->indent = $mod->indent;
|
||||
$cm->completion = $mod->completion;
|
||||
$cm->extra = isset($mod->extra) ? urldecode($mod->extra) : '';
|
||||
$cm->icon = isset($mod->icon) ? $mod->icon : '';
|
||||
$cm->uservisible = true;
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
// We must have completion information from modinfo. If it's not
|
||||
// there, cache needs rebuilding
|
||||
if(!isset($mod->availablefrom)) {
|
||||
debugging('enableavailability option was changed; rebuilding '.
|
||||
'cache for course '.$course->id);
|
||||
rebuild_course_cache($course->id,true);
|
||||
// Re-enter this routine to do it all properly
|
||||
return get_fast_modinfo($course,$userid);
|
||||
}
|
||||
$cm->availablefrom = $mod->availablefrom;
|
||||
$cm->availableuntil = $mod->availableuntil;
|
||||
$cm->showavailability = $mod->showavailability;
|
||||
$cm->conditionscompletion = $mod->conditionscompletion;
|
||||
$cm->conditionsgrade = $mod->conditionsgrade;
|
||||
}
|
||||
|
||||
// preload long names plurals and also check module is installed properly
|
||||
if (!isset($modlurals[$cm->modname])) {
|
||||
@ -1145,7 +1179,29 @@ function &get_fast_modinfo(&$course, $userid=0) {
|
||||
}
|
||||
$cm->modplural = $modlurals[$cm->modname];
|
||||
|
||||
if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', $contexts[$cm->id], $userid)) {
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
// Unfortunately the next call really wants to call
|
||||
// get_fast_modinfo, but that would be recursive, so we fake up a
|
||||
// modinfo for it already
|
||||
if(empty($minimalmodinfo)) {
|
||||
$minimalmodinfo=new stdClass();
|
||||
$minimalmodinfo->cms=array();
|
||||
foreach($info as $mod) {
|
||||
$minimalcm=new stdClass();
|
||||
$minimalcm->id=$mod->cm;
|
||||
$minimalcm->name=urldecode($mod->name);
|
||||
$minimalmodinfo->cms[$minimalcm->id]=$minimalcm;
|
||||
}
|
||||
}
|
||||
|
||||
// Get availability information
|
||||
$ci = new condition_info($cm);
|
||||
$cm->available=$ci->is_available($cm->availableinfo,true,$userid,
|
||||
$minimalmodinfo);
|
||||
} else {
|
||||
$cm->available=true;
|
||||
}
|
||||
if ((!$cm->visible or !$cm->available) and !has_capability('moodle/course:viewhiddenactivities', $contexts[$cm->id], $userid)) {
|
||||
$cm->uservisible = false;
|
||||
|
||||
} else if (!empty($CFG->enablegroupings) and !empty($cm->groupmembersonly)
|
||||
@ -1183,7 +1239,7 @@ function &get_fast_modinfo(&$course, $userid=0) {
|
||||
* Returns a number of useful structures for course displays
|
||||
*/
|
||||
function get_all_mods($courseid, &$mods, &$modnames, &$modnamesplural, &$modnamesused) {
|
||||
global $DB;
|
||||
global $DB,$COURSE;
|
||||
|
||||
$mods = array(); // course modules indexed by id
|
||||
$modnames = array(); // all course module names (except resource!)
|
||||
@ -1202,7 +1258,10 @@ function get_all_mods($courseid, &$mods, &$modnames, &$modnamesplural, &$modname
|
||||
print_error("nomodules", 'debug');
|
||||
}
|
||||
|
||||
if ($rawmods = get_course_mods($courseid)) {
|
||||
$course = ($courseid==$COURSE->id) ? $COURSE : $DB->get_record('course',array('id'=>$courseid));
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
|
||||
if ($rawmods=$modinfo->cms) {
|
||||
foreach($rawmods as $mod) { // Index the mods
|
||||
if (empty($modnames[$mod->modname])) {
|
||||
continue;
|
||||
@ -1336,7 +1395,8 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
|
||||
}
|
||||
|
||||
if (isset($modinfo->cms[$modnumber])) {
|
||||
if (!$modinfo->cms[$modnumber]->uservisible) {
|
||||
if (!$modinfo->cms[$modnumber]->uservisible &&
|
||||
empty($modinfo->cms[$modnumber]->showavailability)) {
|
||||
// visibility shortcut
|
||||
continue;
|
||||
}
|
||||
@ -1345,7 +1405,8 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
|
||||
// module not installed
|
||||
continue;
|
||||
}
|
||||
if (!coursemodule_visible_for_user($mod)) {
|
||||
if (!coursemodule_visible_for_user($mod) &&
|
||||
empty($mod->showavailability)) {
|
||||
// full visibility check
|
||||
continue;
|
||||
}
|
||||
@ -1366,11 +1427,11 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
|
||||
|
||||
$extra = '';
|
||||
if (!empty($modinfo->cms[$modnumber]->extra)) {
|
||||
$extra = $modinfo->cms[$modnumber]->extra;
|
||||
$extra = $modinfo->cms[$modnumber]->extra;
|
||||
}
|
||||
|
||||
if ($mod->modname == "label") {
|
||||
if (!$mod->visible) {
|
||||
if (!$mod->visible || !$mod->uservisible) {
|
||||
echo "<div class=\"dimmed_text\">";
|
||||
}
|
||||
echo format_text($extra, FORMAT_HTML, $labelformatoptions);
|
||||
@ -1416,17 +1477,27 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
|
||||
$altname = get_accesshide(' '.$altname);
|
||||
}
|
||||
|
||||
$linkcss = $mod->visible ? "" : " class=\"dimmed\" ";
|
||||
echo '<a '.$linkcss.' '.$extra. // Title unnecessary!
|
||||
' href="'.$CFG->wwwroot.'/mod/'.$mod->modname.'/view.php?id='.$mod->id.'">'.
|
||||
'<img src="'.$icon.'" class="activityicon" alt="" /> <span>'.
|
||||
$instancename.$altname.'</span></a>';
|
||||
// We may be displaying this just in order to show information
|
||||
// about visibility, without the actual link
|
||||
if($mod->uservisible) {
|
||||
// Display normal module link
|
||||
$linkcss = $mod->visible ? "" : " class=\"dimmed\" ";
|
||||
echo '<a '.$linkcss.' '.$extra. // Title unnecessary!
|
||||
' href="'.$CFG->wwwroot.'/mod/'.$mod->modname.'/view.php?id='.$mod->id.'">'.
|
||||
'<img src="'.$icon.'" class="activityicon" alt="" /> <span>'.
|
||||
$instancename.$altname.'</span></a>';
|
||||
|
||||
if (!empty($CFG->enablegroupings) && !empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
|
||||
if (!isset($groupings)) {
|
||||
$groupings = groups_get_all_groupings($course->id);
|
||||
if (!empty($CFG->enablegroupings) && !empty($mod->groupingid) && has_capability('moodle/course:managegroups', get_context_instance(CONTEXT_COURSE, $course->id))) {
|
||||
if (!isset($groupings)) {
|
||||
$groupings = groups_get_all_groupings($course->id);
|
||||
}
|
||||
echo " <span class=\"groupinglabel\">(".format_string($groupings[$mod->groupingid]->name).')</span>';
|
||||
}
|
||||
echo " <span class=\"groupinglabel\">(".format_string($groupings[$mod->groupingid]->name).')</span>';
|
||||
} else {
|
||||
// Display greyed-out text of link
|
||||
echo '<span class="dimmed_text" '.$extra.' >'.
|
||||
'<img src="'.$icon.'" class="activityicon" alt="" /> <span>'.
|
||||
$instancename.$altname.'</span></span>';
|
||||
}
|
||||
}
|
||||
if ($usetracking && $mod->modname == 'forum') {
|
||||
@ -1460,7 +1531,8 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
|
||||
$completion=$hidecompletion
|
||||
? COMPLETION_TRACKING_NONE
|
||||
: $completioninfo->is_enabled($mod);
|
||||
if($completion!=COMPLETION_TRACKING_NONE && isloggedin() && !isguestuser()) {
|
||||
if($completion!=COMPLETION_TRACKING_NONE && isloggedin() &&
|
||||
!isguestuser() && $mod->uservisible) {
|
||||
$completiondata=$completioninfo->get_data($mod,true);
|
||||
$completionicon='';
|
||||
if($isediting) {
|
||||
@ -1524,6 +1596,21 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
|
||||
}
|
||||
}
|
||||
|
||||
// Show availability information (for someone who isn't allowed to
|
||||
// see the activity itself, or for staff)
|
||||
if(!$mod->uservisible) {
|
||||
echo '<div class="availabilityinfo">'.$mod->availableinfo.'</div>';
|
||||
} else if($isediting && !empty($CFG->enableavailability)) {
|
||||
$ci = new condition_info($mod);
|
||||
$fullinfo=$ci->get_full_information();
|
||||
if($fullinfo) {
|
||||
echo '<div class="availabilityinfo">'.get_string($mod->showavailability
|
||||
? 'userrestriction_visible'
|
||||
: 'userrestriction_hidden','condition',
|
||||
$fullinfo).'</div>';
|
||||
}
|
||||
}
|
||||
|
||||
echo "</li>\n";
|
||||
}
|
||||
|
||||
|
@ -172,6 +172,8 @@
|
||||
print_error('cannotupdatelevel');
|
||||
}
|
||||
|
||||
rebuild_course_cache($cm->course);
|
||||
|
||||
if (SITEID == $cm->course) {
|
||||
redirect($CFG->wwwroot);
|
||||
} else {
|
||||
|
@ -6,6 +6,7 @@
|
||||
require_once("lib.php");
|
||||
require_once($CFG->libdir.'/gradelib.php');
|
||||
require_once($CFG->libdir.'/completionlib.php');
|
||||
require_once($CFG->libdir.'/conditionlib.php');
|
||||
|
||||
$add = optional_param('add', 0, PARAM_ALPHA);
|
||||
$update = optional_param('update', 0, PARAM_INT);
|
||||
@ -123,6 +124,11 @@
|
||||
$form->completionview = $cm->completionview;
|
||||
$form->completionexpected = $cm->completionexpected;
|
||||
$form->completionusegrade = is_null($cm->completiongradeitemnumber) ? 0 : 1;
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
$form->availablefrom = $cm->availablefrom;
|
||||
$form->availableuntil = $cm->availableuntil;
|
||||
$form->showavailability = $cm->showavailability;
|
||||
}
|
||||
|
||||
if ($items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$form->modulename,
|
||||
'iteminstance'=>$form->instance, 'courseid'=>$course->id))) {
|
||||
@ -285,6 +291,12 @@
|
||||
$cm->completionview = $fromform->completionview;
|
||||
$cm->completionexpected = $fromform->completionexpected;
|
||||
}
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
$cm->availablefrom = $fromform->availablefrom;
|
||||
$cm->availableuntil = $fromform->availableuntil;
|
||||
$cm->showavailability = $fromform->showavailability;
|
||||
condition_info::update_cm_from_form($cm,$fromform,true);
|
||||
}
|
||||
|
||||
if (!$DB->update_record('course_modules', $cm)) {
|
||||
print_error('cannotupdatecoursemodule');
|
||||
@ -335,6 +347,11 @@
|
||||
$newcm->completionview = $fromform->completionview;
|
||||
$newcm->completionexpected = $fromform->completionexpected;
|
||||
}
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
$newcm->availablefrom = $fromform->availablefrom;
|
||||
$newcm->availableuntil = $fromform->availableuntil;
|
||||
$newcm->showavailability = $fromform->showavailability;
|
||||
}
|
||||
|
||||
if (!$fromform->coursemodule = add_course_module($newcm)) {
|
||||
print_error('cannotaddcoursemodule');
|
||||
@ -381,6 +398,12 @@
|
||||
set_coursemodule_idnumber($fromform->coursemodule, $fromform->cmidnumber);
|
||||
}
|
||||
|
||||
// Set up conditions
|
||||
if($CFG->enableavailability) {
|
||||
condition_info::update_cm_from_form(
|
||||
(object)array('id'=>$fromform->coursemodule),$fromform,false);
|
||||
}
|
||||
|
||||
add_to_log($course->id, "course", "add mod",
|
||||
"../mod/$fromform->modulename/view.php?id=$fromform->coursemodule",
|
||||
"$fromform->modulename $fromform->instance");
|
||||
|
@ -1,6 +1,11 @@
|
||||
<?php //$Id$
|
||||
require_once ($CFG->libdir.'/formslib.php');
|
||||
require_once($CFG->libdir.'/completionlib.php');
|
||||
if(!empty($CFG->enablecompletion)) {
|
||||
require_once($CFG->libdir.'/completionlib.php');
|
||||
}
|
||||
if(!empty($CFG->enableavailability)) {
|
||||
require_once($CFG->libdir.'/conditionlib.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* This class adds extra methods to form wrapper specific to be used for module
|
||||
@ -174,6 +179,33 @@ class moodleform_mod extends moodleform {
|
||||
$mform->freeze($this->_customcompletionelements);
|
||||
}
|
||||
}
|
||||
|
||||
// Availability conditions
|
||||
if (!empty($CFG->enableavailability) && $this->_cm) {
|
||||
$ci = new condition_info($this->_cm);
|
||||
$fullcm=$ci->get_full_course_module();
|
||||
|
||||
$num=0;
|
||||
foreach($fullcm->conditionsgrade as $gradeitemid=>$minmax) {
|
||||
$groupelements=$mform->getElement('conditiongradegroup['.$num.']')->getElements();
|
||||
$groupelements[0]->setValue($gradeitemid);
|
||||
// These numbers are always in the format 0.00000 - the rtrims remove any final zeros and,
|
||||
// if it is a whole number, the decimal place.
|
||||
$groupelements[2]->setValue(is_null($minmax->min)?'':rtrim(rtrim($minmax->min,'0'),'.'));
|
||||
$groupelements[4]->setValue(is_null($minmax->max)?'':rtrim(rtrim($minmax->max,'0'),'.'));
|
||||
$num++;
|
||||
}
|
||||
|
||||
if ($completion->is_enabled()) {
|
||||
$num=0;
|
||||
foreach($fullcm->conditionscompletion as $othercmid=>$state) {
|
||||
$groupelements=$mform->getElement('conditioncompletiongroup['.$num.']')->getElements();
|
||||
$groupelements[0]->setValue($othercmid);
|
||||
$groupelements[1]->setValue($state);
|
||||
$num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// form verification
|
||||
@ -230,8 +262,9 @@ class moodleform_mod extends moodleform {
|
||||
if (is_object($default_values)) {
|
||||
$default_values = (array)$default_values;
|
||||
}
|
||||
$this->data_preprocessing($default_values);
|
||||
parent::set_data($default_values); //never slashed for moodleform_mod
|
||||
|
||||
$this->data_preprocessing($default_values);
|
||||
parent::set_data($default_values);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -352,8 +385,90 @@ class moodleform_mod extends moodleform {
|
||||
$mform->addElement('select', 'gradecat', get_string('gradecategory', 'grades'), $categories);
|
||||
}
|
||||
|
||||
if (!empty($CFG->enableavailability)) {
|
||||
// Conditional availability
|
||||
$mform->addElement('header', '', get_string('availabilityconditions', 'condition'));
|
||||
$mform->addElement('date_selector', 'availablefrom', get_string('availablefrom', 'condition'), array('optional'=>true));
|
||||
$mform->setHelpButton('availablefrom', array('conditiondates', get_string('help_conditiondates', 'condition'), 'condition'));
|
||||
$mform->addElement('date_selector', 'availableuntil', get_string('availableuntil', 'condition'), array('optional'=>true));
|
||||
$mform->setHelpButton('availableuntil', array('conditiondates', get_string('help_conditiondates', 'condition'), 'condition'));
|
||||
|
||||
// Conditions based on grades
|
||||
$gradeoptions=array();
|
||||
$items=grade_item::fetch_all(array('courseid'=>$COURSE->id));
|
||||
foreach($items as $id=>$item) {
|
||||
$gradeoptions[$id]=$item->get_name();
|
||||
}
|
||||
asort($gradeoptions);
|
||||
$gradeoptions=array(0=>get_string('none','condition'))+$gradeoptions;
|
||||
|
||||
$grouparray=array();
|
||||
$grouparray[] =& $mform->createElement('select','conditiongradeitemid','',$gradeoptions);
|
||||
$grouparray[] =& $mform->createElement('static', '', '',' '.get_string('grade_atleast','condition'));
|
||||
$grouparray[] =& $mform->createElement('text', 'conditiongrademin','',array('size'=>3));
|
||||
$grouparray[] =& $mform->createElement('static', '', '',' '.get_string('grade_upto','condition'));
|
||||
$grouparray[] =& $mform->createElement('text', 'conditiongrademax','',array('size'=>3));
|
||||
$mform->setType('conditiongrademin',PARAM_FLOAT);
|
||||
$mform->setType('conditiongrademax',PARAM_FLOAT);
|
||||
$group = $mform->createElement('group','conditiongradegroup',
|
||||
get_string('gradecondition', 'condition'),$grouparray);
|
||||
|
||||
// Get version with condition info and store it so we don't ask
|
||||
// twice
|
||||
if(!empty($this->_cm)) {
|
||||
$ci = new condition_info($this->_cm,CONDITION_MISSING_EXTRATABLE);
|
||||
$this->_cm=$ci->get_full_course_module();
|
||||
$count=count($this->_cm->conditionsgrade)+1;
|
||||
} else {
|
||||
$count=1;
|
||||
}
|
||||
|
||||
$this->repeat_elements(array($group),$count,array(),'conditiongraderepeats','conditiongradeadds',2,
|
||||
get_string('addgrades','condition'),true);
|
||||
$mform->setHelpButton('conditiongradegroup[0]', array('gradecondition', get_string('help_gradecondition', 'condition'), 'condition'));
|
||||
|
||||
// Conditions based on completion
|
||||
$completion = new completion_info($COURSE);
|
||||
if ($completion->is_enabled()) {
|
||||
$completionoptions=array();
|
||||
$modinfo=get_fast_modinfo($COURSE);
|
||||
foreach($modinfo->cms as $id=>$cm) {
|
||||
$completionoptions[$id]=$cm->name;
|
||||
}
|
||||
asort($completionoptions);
|
||||
$completionoptions=array(0=>get_string('none','condition'))+$completionoptions;
|
||||
|
||||
$completionvalues=array(
|
||||
COMPLETION_COMPLETE=>get_string('completion_complete','condition'),
|
||||
COMPLETION_INCOMPLETE=>get_string('completion_incomplete','condition'),
|
||||
COMPLETION_COMPLETE_PASS=>get_string('completion_pass','condition'),
|
||||
COMPLETION_COMPLETE_FAIL=>get_string('completion_fail','condition'));
|
||||
|
||||
$grouparray=array();
|
||||
$grouparray[] =& $mform->createElement('select','conditionsourcecmid','',$completionoptions);
|
||||
$grouparray[] =& $mform->createElement('select','conditionrequiredcompletion','',$completionvalues);
|
||||
$group = $mform->createElement('group','conditioncompletiongroup',
|
||||
get_string('completioncondition', 'condition'),$grouparray);
|
||||
|
||||
$count=empty($this->_cm) ? 1 : count($this->_cm->conditionscompletion)+1;
|
||||
$this->repeat_elements(array($group),$count,array(),
|
||||
'conditioncompletionrepeats','conditioncompletionadds',2,
|
||||
get_string('addcompletions','condition'),true);
|
||||
$mform->setHelpButton('conditioncompletiongroup[0]', array('completioncondition', get_string('help_completioncondition', 'condition'), 'condition'));
|
||||
}
|
||||
|
||||
// Do we display availability info to students?
|
||||
$mform->addElement('select', 'showavailability', get_string('showavailability', 'condition'),
|
||||
array(CONDITION_STUDENTVIEW_SHOW=>get_string('showavailability_show', 'condition'),
|
||||
CONDITION_STUDENTVIEW_HIDE=>get_string('showavailability_hide', 'condition')));
|
||||
$mform->setDefault('showavailability', CONDITION_STUDENTVIEW_SHOW);
|
||||
$mform->setHelpButton('showavailability', array('showavailability', get_string('help_showavailability', 'condition'), 'condition'));
|
||||
}
|
||||
|
||||
// Conditional activities: completion tracking section
|
||||
$completion = new completion_info($COURSE);
|
||||
if(!isset($completion)) {
|
||||
$completion = new completion_info($COURSE);
|
||||
}
|
||||
if ($completion->is_enabled()) {
|
||||
$mform->addElement('header', '', get_string('activitycompletion', 'completion'));
|
||||
|
||||
@ -362,7 +477,7 @@ class moodleform_mod extends moodleform {
|
||||
$mform->addElement('submit', 'unlockcompletion', get_string('unlockcompletion', 'completion'));
|
||||
$mform->registerNoSubmitButton('unlockcompletion');
|
||||
$mform->addElement('hidden', 'completionunlocked', 0);
|
||||
|
||||
|
||||
$mform->addElement('select', 'completion', get_string('completion', 'completion'),
|
||||
array(COMPLETION_TRACKING_NONE=>get_string('completion_none', 'completion'),
|
||||
COMPLETION_TRACKING_MANUAL=>get_string('completion_manual', 'completion')));
|
||||
|
35
lang/en_utf8/condition.php
Normal file
35
lang/en_utf8/condition.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
$string['addgrades']='Add {no} grade conditions to form';
|
||||
$string['addcompletions']='Add {no} activity conditions to form';
|
||||
$string['availabilityconditions']='Restrict availability';
|
||||
$string['availablefrom']='Only available from';
|
||||
$string['availableuntil']='Only available until';
|
||||
$string['completion_complete']=' must be marked complete';
|
||||
$string['completion_incomplete']=' must not be marked complete';
|
||||
$string['completion_pass']=' must be complete with pass grade';
|
||||
$string['completion_fail']=' must be complete with fail grade';
|
||||
$string['configenableavailability']='When enabled, this lets you set conditions (based on date, grade, or completion) that control whether an activity is available.';
|
||||
$string['enableavailability']='Enable conditional availability';
|
||||
$string['grade_atleast']='must be ≥';
|
||||
$string['grade_upto']='and <';
|
||||
$string['gradecondition']='Grade condition';
|
||||
$string['completioncondition']='Activity completion condition';
|
||||
$string['help_conditiondates']='available dates';
|
||||
$string['help_showavailability']='display of unavailable activities';
|
||||
$string['none']='(none)';
|
||||
$string['requires_completion_0']='Not available unless the activity <strong>$a</strong> is incomplete.';
|
||||
$string['requires_completion_1']='Not available until the activity <strong>$a</strong> is marked complete.';
|
||||
$string['requires_completion_2']='Not available until the activity <strong>$a</strong> is complete and passed.';
|
||||
$string['requires_completion_3']='Not available unless the activity <strong>$a</strong> is complete and failed.';
|
||||
$string['requires_date']='Not available until $a.';
|
||||
$string['requires_date_before']='Not available from $a.';
|
||||
$string['requires_grade_any']='Not available until you have a grade in <strong>$a</strong>.';
|
||||
$string['requires_grade_min']='Not available until you achieve a required score in <strong>$a</strong>.';
|
||||
$string['requires_grade_max']='Not available unless you get an appropriate score in <strong>$a</strong>.';
|
||||
$string['requires_grade_range']='Not available unless you get a particular score in <strong>$a</strong>.';
|
||||
$string['showavailability']='Before activity is available';
|
||||
$string['showavailability_show']='Show activity greyed-out, with restriction information';
|
||||
$string['showavailability_hide']='Hide activity entirely';
|
||||
$string['userrestriction_visible']='Activity conditionally restricted: ‘$a’';
|
||||
$string['userrestriction_hidden']='Activity conditionally restricted (completely hidden, no message): ‘$a’';
|
||||
?>
|
20
lang/en_utf8/help/condition/completioncondition.html
Normal file
20
lang/en_utf8/help/condition/completioncondition.html
Normal file
@ -0,0 +1,20 @@
|
||||
<h1>Activity completion condition</h1>
|
||||
|
||||
<p>
|
||||
You can set a condition based on whether the user has completed another
|
||||
activity.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This feature uses the completion options that have been configured for the
|
||||
other activity. You can choose whether the activity must be complete,
|
||||
incomplete, complete and passed, or complete and failed. The final two
|
||||
options only work if you use grade-based completion and set a pass mark on
|
||||
the grade item. (Please look at the documentation for activity completion
|
||||
if this is unclear.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can add more than one completion condition. All conditions must be met in
|
||||
order for the activity to appear.
|
||||
</p>
|
23
lang/en_utf8/help/condition/conditiondates.html
Normal file
23
lang/en_utf8/help/condition/conditiondates.html
Normal file
@ -0,0 +1,23 @@
|
||||
<h1>Available dates</h1>
|
||||
|
||||
<p>
|
||||
Using the 'Only available from' and 'Only available until' dates, you can make
|
||||
an activity appear or disappear. The activity is only shown to students from the
|
||||
'available from' date, and it disappears on the 'available until' date. Students
|
||||
cannot access it outside those times, even if they guess the URL.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
By default both dates are disabled, meaning that the activity is available at
|
||||
any time (as long as the student can access the course).
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> If you choose to show information about an activity that is unavailable,
|
||||
then before the 'available from' date, students will see the activity
|
||||
greyed-out, with informational text about the date that it appears.</li>
|
||||
<li> The activity completely vanishes on the 'available to' date, even if
|
||||
you've chosen to show information.</li>
|
||||
<li> Setting 'Visible' to 'Hide' overrides these settings. If you set 'Visible'
|
||||
to 'Hide', the activity is never available regardless of date.</li>
|
||||
</ul>
|
31
lang/en_utf8/help/condition/gradecondition.html
Normal file
31
lang/en_utf8/help/condition/gradecondition.html
Normal file
@ -0,0 +1,31 @@
|
||||
<h1>Grade condition</h1>
|
||||
|
||||
<p>
|
||||
You can specify a condition on any grade in the course: the full course grade,
|
||||
the grade for any activity, or a custom grade that you create manually.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can enter either a minimum value (≥), a maximum value (<), both, or
|
||||
neither. The activity will only appear if the student has a value for the
|
||||
specified grade, and if it falls within any specified number range.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can add more than one grade condition. All conditions must be met in order
|
||||
for the activity to appear.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>The range numbers can be fractional (with up to five decimal places) if
|
||||
necessary. </li>
|
||||
<li>Be careful with the maximum value; if the maximum is 7, a student who
|
||||
scores exactly 7 will not see the activity. You could set it to 7.01 if
|
||||
you really wanted to include 7.</li>
|
||||
<li>If creating several different activities that appear according to grade
|
||||
ranges, use the same number for the maximum of one activity, and the minimum
|
||||
of the next. For example, you might create one activity with a maximum of 7
|
||||
and another with a minimum of 7. The first would appear to everyone scoring
|
||||
between 0 and 6.99999, and the second would appear to everyone scoring 7.00000
|
||||
to 10. This guarantees that everyone with a grade will see one or other.</li>
|
||||
</ul>
|
27
lang/en_utf8/help/condition/showavailability.html
Normal file
27
lang/en_utf8/help/condition/showavailability.html
Normal file
@ -0,0 +1,27 @@
|
||||
<h1>Unavailable activity display</h1>
|
||||
|
||||
<p>
|
||||
When an activity is unavailable due to the restrictions in this box, there are
|
||||
two possibilities:
|
||||
</p>
|
||||
|
||||
<ol>
|
||||
<li> The activity displays to users, but as greyed-out text instead of a link.
|
||||
Informational text below the activity indicates when, or under what
|
||||
conditions, it will become available.</li>
|
||||
<li> The activity does not display to users at all.</li>
|
||||
</ol>
|
||||
|
||||
<p>
|
||||
In both cases, once the activity becomes available, it displays as normal.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Users with the 'view hidden activities' capability can still see
|
||||
unavailable activities, regardless of this setting. The informational text
|
||||
always appears to them.</li>
|
||||
<li>This option does not affect the standard 'visibility' option (also controlled
|
||||
by the eye icon). You can still use this icon to quickly and completely hide
|
||||
any activity from students, for example if you find a problem with the
|
||||
activity.</li>
|
||||
</ul>
|
@ -394,13 +394,15 @@ class completion_info {
|
||||
* Obtains completion data for a particular activity and user (from the
|
||||
* session cache if available, or by SQL query)
|
||||
*
|
||||
* @param object $cm Activity
|
||||
* @param object $cm Activity; only required field is ->id
|
||||
* @param bool $wholecourse If true (default false) then, when necessary to
|
||||
* fill the cache, retrieves information from the entire course not just for
|
||||
* this one activity
|
||||
* @param int $userid User ID or 0 (default) for current user
|
||||
* @param array $modinfo For unit testing only, supply the value
|
||||
* here. Otherwise the method calls get_fast_modinfo
|
||||
* @param array $modinfo Supply the value here - this is used for unit
|
||||
* testing and so that it can be called recursively from within
|
||||
* get_fast_modinfo. (Needs only list of all CMs with IDs.)
|
||||
* Otherwise the method calls get_fast_modinfo itself.
|
||||
* @return object Completion data (record from course_modules_completion)
|
||||
* @throws Exception In some cases where the requested course-module is not
|
||||
* found on the specified course
|
||||
@ -632,7 +634,7 @@ class completion_info {
|
||||
foreach ($users as $user) {
|
||||
$userids[] = $user->id;
|
||||
$resultobject->users[$user->id]=$user;
|
||||
$resultobject->users[$user->id]->progress=array();
|
||||
$resultobject->users[$user->id]->progress=array();
|
||||
}
|
||||
|
||||
for($i=0; $i<count($userids); $i+=1000) {
|
||||
@ -716,22 +718,24 @@ WHERE
|
||||
}
|
||||
|
||||
/**
|
||||
* This temporary function is intended to be replaced once a Moodle exception
|
||||
* system is agreed. Code that used to call this function should instead
|
||||
* throw an exception, so this function should be deleted. The function is
|
||||
* only used internally.
|
||||
*
|
||||
* This is to be used only for system errors (things that shouldn't happen)
|
||||
* and not user-level errors.
|
||||
*
|
||||
* @param string $error Error string (will not be displayed to user unless
|
||||
* debugging is enabled)
|
||||
* @throws moodle_exception Exception with the error string as debug info
|
||||
*/
|
||||
function internal_systemerror($error) {
|
||||
global $CFG;
|
||||
throw new moodle_exception('err_system','completion',
|
||||
$CFG->wwwroot.'/course/view.php?id='.$this->course->id,null,$error);
|
||||
}
|
||||
|
||||
debugging($error, DEBUG_ALL);
|
||||
print_error('err_system', 'completion', $CFG->wwwroot.'/course/view.php?id='.$this->course->id);
|
||||
/** For testing only. Wipes information cached in user session. */
|
||||
static function wipe_session_cache() {
|
||||
global $SESSION;
|
||||
unset($SESSION->completioncache);
|
||||
unset($SESSION->completioncacheuserid);
|
||||
}
|
||||
}
|
||||
|
||||
|
538
lib/conditionlib.php
Normal file
538
lib/conditionlib.php
Normal file
@ -0,0 +1,538 @@
|
||||
<?php
|
||||
// Used for tracking conditions that apply before activities are displayed
|
||||
// to students ('conditional availability').
|
||||
|
||||
/** The activity is not displayed to students at all when conditions aren't met. */
|
||||
define('CONDITION_STUDENTVIEW_HIDE',0);
|
||||
/** The activity is displayed to students as a greyed-out name, with informational
|
||||
text that explains the conditions under which it will be available. */
|
||||
define('CONDITION_STUDENTVIEW_SHOW',1);
|
||||
|
||||
/** The $cm variable is expected to contain all completion-related data */
|
||||
define('CONDITION_MISSING_NOTHING',0);
|
||||
/** The $cm variable is expected to contain the fields from course_modules but
|
||||
not the course_modules_availability data */
|
||||
define('CONDITION_MISSING_EXTRATABLE',1);
|
||||
/** The $cm variable is expected to contain nothing except the ID */
|
||||
define('CONDITION_MISSING_EVERYTHING',2);
|
||||
|
||||
class condition_info {
|
||||
private $cm,$gotdata;
|
||||
|
||||
/**
|
||||
* Constructs with course-module details.
|
||||
*
|
||||
* @param object $cm Moodle course-module object. May have extra fields
|
||||
* ->conditionsgrade, ->conditionscompletion which should come from
|
||||
* get_fast_modinfo. Should have ->availablefrom, ->availableuntil,
|
||||
* and ->showavailability, ->course; but the only required thing is ->id.
|
||||
* @param int $expectingmissing Used to control whether or not a developer
|
||||
* debugging message (performance warning) will be displayed if some of
|
||||
* the above data is missing and needs to be retrieved; a
|
||||
* CONDITION_MISSING_xx constant
|
||||
* @param bool $loaddata If you need a 'write-only' object, set this value
|
||||
* to false to prevent database access from constructor
|
||||
* @return condition_info Object which can retrieve information about the
|
||||
* activity
|
||||
*/
|
||||
public function __construct($cm,$expectingmissing=CONDITION_MISSING_NOTHING,
|
||||
$loaddata=true) {
|
||||
global $DB;
|
||||
|
||||
// Check ID as otherwise we can't do the other queries
|
||||
if(empty($cm->id)) {
|
||||
throw new coding_exception("Invalid parameters; course-module ID not included");
|
||||
}
|
||||
|
||||
// If not loading data, don't do anything else
|
||||
if(!$loaddata) {
|
||||
$this->cm=(object)array('id'=>$cm->id);
|
||||
$this->gotdata=false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Missing basic data from course_modules
|
||||
if(!isset($cm->availablefrom) || !isset($cm->availableuntil) ||
|
||||
!isset($cm->showavailability) || !isset($cm->course)) {
|
||||
if($expectingmissing<CONDITION_MISSING_EVERYTHING) {
|
||||
debugging('Performance warning: condition_info constructor is
|
||||
faster if you pass in $cm with at least basic fields
|
||||
(availablefrom,availableuntil,showavailability,course).
|
||||
[This warning can be disabled, see phpdoc.]',
|
||||
DEBUG_DEVELOPER);
|
||||
}
|
||||
$cm=$DB->get_record('course_modules',array('id'=>$cm->id),
|
||||
'id,course,availablefrom,availableuntil,showavailability');
|
||||
}
|
||||
|
||||
$this->cm=clone($cm);
|
||||
$this->gotdata=true;
|
||||
|
||||
// Missing extra data
|
||||
if(!isset($cm->conditionsgrade) || !isset($cm->conditionscompletion)) {
|
||||
if($expectingmissing<CONDITION_MISSING_EXTRATABLE) {
|
||||
debugging('Performance warning: condition_info constructor is
|
||||
faster if you pass in a $cm from get_fast_modinfo.
|
||||
[This warning can be disabled, see phpdoc.]',
|
||||
DEBUG_DEVELOPER);
|
||||
}
|
||||
|
||||
self::fill_availability_conditions($this->cm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the extra availability conditions (if any) into the given
|
||||
* course-module object.
|
||||
*
|
||||
* @param object &$cm Moodle course-module data object
|
||||
*/
|
||||
public static function fill_availability_conditions(&$cm) {
|
||||
if(empty($cm->id)) {
|
||||
throw new coding_exception("Invalid parameters; course-module ID not included");
|
||||
}
|
||||
|
||||
// Does nothing if the variables are already present
|
||||
if(!isset($cm->conditionsgrade) ||
|
||||
!isset($cm->conditionscompletion)) {
|
||||
$cm->conditionsgrade=array();
|
||||
$cm->conditionscompletion=array();
|
||||
|
||||
global $DB,$CFG;
|
||||
$conditions=$DB->get_records_sql($sql="
|
||||
SELECT
|
||||
cma.id as cmaid, gi.*,cma.sourcecmid,cma.requiredcompletion,cma.gradeitemid,
|
||||
cma.grademin as conditiongrademin, cma.grademax as conditiongrademax
|
||||
FROM
|
||||
{course_modules_availability} cma
|
||||
LEFT JOIN {grade_items} gi ON gi.id=cma.gradeitemid
|
||||
WHERE
|
||||
coursemoduleid=?",array($cm->id));
|
||||
foreach($conditions as $condition) {
|
||||
if(!is_null($condition->sourcecmid)) {
|
||||
$cm->conditionscompletion[$condition->sourcecmid]=
|
||||
$condition->requiredcompletion;
|
||||
} else {
|
||||
$minmax=new stdClass;
|
||||
$minmax->min=$condition->conditiongrademin;
|
||||
$minmax->max=$condition->conditiongrademax;
|
||||
$minmax->name=self::get_grade_name($condition);
|
||||
$cm->conditionsgrade[$condition->gradeitemid]=$minmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the name of a grade item.
|
||||
* @param object $gradeitemobj Object from get_record on grade_items table,
|
||||
* (can be empty if you want to just get !missing)
|
||||
* @return string Name of item of !missing if it didn't exist
|
||||
*/
|
||||
private static function get_grade_name($gradeitemobj) {
|
||||
global $CFG;
|
||||
if(isset($gradeitemobj->id)) {
|
||||
require_once($CFG->libdir.'/gradelib.php');
|
||||
$item=new grade_item;
|
||||
grade_object::set_properties($item,$gradeitemobj);
|
||||
return $item->get_name();
|
||||
} else {
|
||||
return '!missing'; // Ooops, missing grade
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A course-module object with all the information required to
|
||||
* determine availability.
|
||||
* @throws coding_exception If data wasn't loaded
|
||||
*/
|
||||
public function get_full_course_module() {
|
||||
$this->require_data();
|
||||
return $this->cm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the database a condition based on completion of another module.
|
||||
* @param int $cmid ID of other module
|
||||
* @param int $requiredcompletion COMPLETION_xx constant
|
||||
*/
|
||||
public function add_completion_condition($cmid,$requiredcompletion) {
|
||||
// Add to DB
|
||||
global $DB;
|
||||
$DB->insert_record('course_modules_availability',
|
||||
(object)array('coursemoduleid'=>$this->cm->id,
|
||||
'sourcecmid'=>$cmid,'requiredcompletion'=>$requiredcompletion),
|
||||
false);
|
||||
|
||||
// Store in memory too
|
||||
$this->cm->conditionscompletion[$cmid]=$requiredcompletion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the database a condition based on the value of a grade item.
|
||||
* @param int $gradeitemid ID of grade item
|
||||
* @param float $min Minimum grade (>=), up to 5 decimal points, or null if none
|
||||
* @param float $max Maximum grade (<), up to 5 decimal points, or null if none
|
||||
* @param bool $updateinmemory If true, updates data in memory; otherwise,
|
||||
* memory version may be out of date (this has performance consequences,
|
||||
* so don't do it unless it really needs updating)
|
||||
*/
|
||||
public function add_grade_condition($gradeitemid,$min,$max,$updateinmemory=false) {
|
||||
// Normalise nulls
|
||||
if($min==='') {
|
||||
$min=null;
|
||||
}
|
||||
if($max==='') {
|
||||
$max=null;
|
||||
}
|
||||
// Add to DB
|
||||
global $DB;
|
||||
$DB->insert_record('course_modules_availability',
|
||||
(object)array('coursemoduleid'=>$this->cm->id,
|
||||
'gradeitemid'=>$gradeitemid,'grademin'=>$min,'grademax'=>$max),
|
||||
false);
|
||||
|
||||
// Store in memory too
|
||||
if($updateinmemory) {
|
||||
$this->cm->conditionsgrade[$gradeitemid]=(object)array(
|
||||
'min'=>$min,'max'=>$max);
|
||||
$this->cm->conditionsgrade[$gradeitemid]->name=
|
||||
self::get_grade_name($DB->get_record('grade_items',
|
||||
array('id'=>$gradeitemid)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Erases from the database all conditions for this activity.
|
||||
*/
|
||||
public function wipe_conditions() {
|
||||
// Wipe from DB
|
||||
global $DB;
|
||||
$DB->delete_records('course_modules_availability',
|
||||
array('coursemoduleid'=>$this->cm->id));
|
||||
|
||||
// And from memory
|
||||
$this->cm->conditionsgrade=array();
|
||||
$this->cm->conditionscompletion=array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a string describing all availability restrictions (even if
|
||||
* they do not apply any more).
|
||||
* @param object $modinfo Usually leave as null for default. Specify when
|
||||
* calling recursively from inside get_fast_modinfo. The value supplied
|
||||
* here must include list of all CMs with 'id' and 'name'
|
||||
* @return string Information string (for admin) about all restrictions on
|
||||
* this item
|
||||
* @throws coding_exception If data wasn't loaded
|
||||
*/
|
||||
public function get_full_information($modinfo=null) {
|
||||
$this->require_data();
|
||||
global $COURSE,$DB;
|
||||
|
||||
$information='';
|
||||
|
||||
// Completion conditions
|
||||
if(count($this->cm->conditionscompletion)>0) {
|
||||
if($this->cm->course==$COURSE->id) {
|
||||
$course=$COURSE;
|
||||
} else {
|
||||
$course=$DB->get_record('course',array('id'=>$this->cm->course),'id,enablecompletion,modinfo');
|
||||
}
|
||||
foreach($this->cm->conditionscompletion as $cmid=>$expectedcompletion) {
|
||||
if(!$modinfo) {
|
||||
$modinfo=get_fast_modinfo($course);
|
||||
}
|
||||
$information.=get_string(
|
||||
'requires_completion_'.$expectedcompletion,
|
||||
'condition',$modinfo->cms[$cmid]->name).' ';
|
||||
}
|
||||
}
|
||||
|
||||
// Grade conditions
|
||||
if(count($this->cm->conditionsgrade)>0) {
|
||||
foreach($this->cm->conditionsgrade as $gradeitemid=>$minmax) {
|
||||
// String depends on type of requirement. We are coy about
|
||||
// the actual numbers, in case grades aren't released to
|
||||
// students.
|
||||
if(is_null($minmax->min) && is_null($minmax->max)) {
|
||||
$string='any';
|
||||
} else if(is_null($minmax->max)) {
|
||||
$string='min';
|
||||
} else if(is_null($minmax->min)) {
|
||||
$string='max';
|
||||
} else {
|
||||
$string='range';
|
||||
}
|
||||
$information.=get_string('requires_grade_'.$string,'condition',$minmax->name).' ';
|
||||
}
|
||||
}
|
||||
|
||||
// Dates
|
||||
if($this->cm->availablefrom) {
|
||||
$information.=get_string('requires_date','condition',userdate(
|
||||
$this->cm->availablefrom,get_string('strftimedate','langconfig')));
|
||||
}
|
||||
|
||||
if($this->cm->availableuntil) {
|
||||
$information.=get_string('requires_date_before','condition',userdate(
|
||||
$this->cm->availableuntil,get_string('strftimedate','langconfig')));
|
||||
}
|
||||
|
||||
$information=trim($information);
|
||||
return $information;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this particular course-module is currently available
|
||||
* according to these criteria.
|
||||
*
|
||||
* - This does not include the 'visible' setting (i.e. this might return
|
||||
* true even if visible is false); visible is handled independently.
|
||||
* - This does not take account of the viewhiddenactivities capability.
|
||||
* That should apply later.
|
||||
*
|
||||
* @param string &$information If the item has availability restrictions,
|
||||
* a string that describes the conditions will be stored in this variable;
|
||||
* if this variable is set blank, that means don't display anything
|
||||
* @param bool $grabthelot Performance hint: if true, caches information
|
||||
* required for all course-modules, to make the front page and similar
|
||||
* pages work more quickly (works only for current user)
|
||||
* @param int $userid If set, specifies a different user ID to check availability for
|
||||
* @param object $modinfo Usually leave as null for default. Specify when
|
||||
* calling recursively from inside get_fast_modinfo. The value supplied
|
||||
* here must include list of all CMs with 'id' and 'name'
|
||||
* @return bool True if this item is available to the user, false otherwise
|
||||
* @throws coding_exception If data wasn't loaded
|
||||
*/
|
||||
public function is_available(&$information,$grabthelot=false,$userid=0,$modinfo=null) {
|
||||
$this->require_data();
|
||||
global $COURSE,$DB;
|
||||
|
||||
$available=true;
|
||||
$information='';
|
||||
|
||||
// Check each completion condition
|
||||
if(count($this->cm->conditionscompletion)>0) {
|
||||
if($this->cm->course==$COURSE->id) {
|
||||
$course=$COURSE;
|
||||
} else {
|
||||
$course=$DB->get_record('course',array('id'=>$this->cm->course),'id,enablecompletion,modinfo');
|
||||
}
|
||||
|
||||
$completion=new completion_info($course);
|
||||
foreach($this->cm->conditionscompletion as $cmid=>$expectedcompletion) {
|
||||
// The completion system caches its own data
|
||||
$completiondata=$completion->get_data((object)array('id'=>$cmid),
|
||||
$grabthelot,$userid,$modinfo);
|
||||
|
||||
$thisisok=true;
|
||||
if($expectedcompletion==COMPLETION_COMPLETE) {
|
||||
// 'Complete' also allows the pass, fail states
|
||||
switch($completiondata->completionstate) {
|
||||
case COMPLETION_COMPLETE:
|
||||
case COMPLETION_COMPLETE_FAIL:
|
||||
case COMPLETION_COMPLETE_PASS:
|
||||
break;
|
||||
default:
|
||||
$thisisok=false;
|
||||
}
|
||||
} else {
|
||||
// Other values require exact match
|
||||
if($completiondata->completionstate!=$expectedcompletion) {
|
||||
$thisisok=false;
|
||||
}
|
||||
}
|
||||
if(!$thisisok) {
|
||||
$available=false;
|
||||
if(!$modinfo) {
|
||||
$modinfo=get_fast_modinfo($course);
|
||||
}
|
||||
$information.=get_string(
|
||||
'requires_completion_'.$expectedcompletion,
|
||||
'condition',$modinfo->cms[$cmid]->name).' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check each grade condition
|
||||
if(count($this->cm->conditionsgrade)>0) {
|
||||
foreach($this->cm->conditionsgrade as $gradeitemid=>$minmax) {
|
||||
$score=$this->get_cached_grade_score($gradeitemid,$grabthelot,$userid);
|
||||
if($score===false ||
|
||||
(!is_null($minmax->min) && $score<$minmax->min) ||
|
||||
(!is_null($minmax->max) && $score>=$minmax->max)) {
|
||||
// Grade fail
|
||||
$available=false;
|
||||
// String depends on type of requirement. We are coy about
|
||||
// the actual numbers, in case grades aren't released to
|
||||
// students.
|
||||
if(is_null($minmax->min) && is_null($minmax->max)) {
|
||||
$string='any';
|
||||
} else if(is_null($minmax->max)) {
|
||||
$string='min';
|
||||
} else if(is_null($minmax->min)) {
|
||||
$string='max';
|
||||
} else {
|
||||
$string='range';
|
||||
}
|
||||
$information.=get_string('requires_grade_'.$string,'condition',$minmax->name).' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test dates
|
||||
if($this->cm->availablefrom) {
|
||||
if(time() < $this->cm->availablefrom) {
|
||||
$available=false;
|
||||
$information.=get_string('requires_date','condition',userdate(
|
||||
$this->cm->availablefrom,get_string('strftimedate','langconfig')));
|
||||
}
|
||||
}
|
||||
|
||||
if($this->cm->availableuntil) {
|
||||
if(time() >= $this->cm->availableuntil) {
|
||||
$available=false;
|
||||
// But we don't display any information about this case. This is
|
||||
// because the only reason to set a 'disappear' date is usually
|
||||
// to get rid of outdated information/clutter in which case there
|
||||
// is no point in showing it...
|
||||
|
||||
// Note it would be nice if we could make it so that the 'until'
|
||||
// date appears below the item while the item is still accessible,
|
||||
// unfortunately this is not possible in the current system. Maybe
|
||||
// later, or if somebody else wants to add it.
|
||||
}
|
||||
}
|
||||
|
||||
$information=trim($information);
|
||||
return $available;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if information about availability should be shown to
|
||||
* normal users
|
||||
* @throws coding_exception If data wasn't loaded
|
||||
*/
|
||||
public function show_availability() {
|
||||
$this->require_data();
|
||||
return $this->cm->showavailability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function cheks that data was loaded.
|
||||
* @throws coding_exception If data wasn't loaded
|
||||
*/
|
||||
private function require_data() {
|
||||
if(!$this->gotdata) {
|
||||
throw new coding_exception('Error: cannot call when info was '.
|
||||
'constructed without data');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a grade score. Note that this score should not be displayed to
|
||||
* the user, because gradebook rules might prohibit that. It may be a
|
||||
* non-final score subject to adjustment later.
|
||||
*
|
||||
* @param int $gradeitemid Grade item ID we're interested in
|
||||
* @param bool $grabthelot If true, grabs all scores for current user on
|
||||
* this course, so that later ones come from cache
|
||||
* @param int $userid Set if requesting grade for a different user (does
|
||||
* not use cache)
|
||||
* @return float Grade score, or false if user does not have a grade yet
|
||||
*/
|
||||
private function get_cached_grade_score($gradeitemid,$grabthelot=false,$userid=0) {
|
||||
global $USER, $DB, $SESSION;
|
||||
if($userid==0 || $userid=$USER->id) {
|
||||
// For current user, go via cache in session
|
||||
if(empty($SESSION->gradescorecache) || $SESSION->gradescorecacheuserid!=$USER->id) {
|
||||
$SESSION->gradescorecache=array();
|
||||
$SESSION->gradescorecacheuserid=$USER->id;
|
||||
}
|
||||
if(!array_key_exists($gradeitemid,$SESSION->gradescorecache)) {
|
||||
if($grabthelot) {
|
||||
// Get all grades for the current course
|
||||
$rs=$DB->get_recordset_sql("
|
||||
SELECT
|
||||
gi.id,gg.finalgrade
|
||||
FROM
|
||||
{grade_items} gi
|
||||
LEFT JOIN {grade_grades} gg ON gi.id=gg.itemid AND gg.userid=?
|
||||
WHERE
|
||||
gi.courseid=?",array($USER->id,$this->cm->course));
|
||||
foreach($rs as $record) {
|
||||
$SESSION->gradescorecache[$record->id]=
|
||||
is_null($record->finalgrade)
|
||||
? false
|
||||
: $record->finalgrade;
|
||||
|
||||
}
|
||||
$rs->close();
|
||||
// And if it's still not set, well it doesn't exist (eg
|
||||
// maybe the user set it as a condition, then deleted the
|
||||
// grade item) so we call it false
|
||||
if(!array_key_exists($gradeitemid,$SESSION->gradescorecache)) {
|
||||
$SESSION->gradescorecache[$gradeitemid]=false;
|
||||
}
|
||||
} else {
|
||||
// Just get current grade
|
||||
$score=$DB->get_field('grade_grades','finalgrade',array(
|
||||
'userid'=>$USER->id,'itemid'=>$gradeitemid));
|
||||
// Treat the case where row exists but is null, same as
|
||||
// case where row doesn't exist
|
||||
if(is_null($score)) {
|
||||
$score=false;
|
||||
}
|
||||
$SESSION->gradescorecache[$gradeitemid]=$score;
|
||||
}
|
||||
}
|
||||
return $SESSION->gradescorecache[$gradeitemid];
|
||||
} else {
|
||||
// Not the current user, so request the score individually
|
||||
$score=$DB->get_field('grade_grades','finalgrade',array(
|
||||
'userid'=>$userid,'itemid'=>$gradeitemid));
|
||||
if($score===null) {
|
||||
$score=false;
|
||||
}
|
||||
return $score;
|
||||
}
|
||||
}
|
||||
|
||||
/** For testing only. Wipes information cached in user session. */
|
||||
static function wipe_session_cache() {
|
||||
global $SESSION;
|
||||
unset($SESSION->gradescorecache);
|
||||
unset($SESSION->gradescorecacheuserid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function called by modedit.php; updates the
|
||||
* course_modules_availability table based on the module form data.
|
||||
*
|
||||
* @param object $cm Course-module with as much data as necessary, min id
|
||||
* @param unknown_type $fromform
|
||||
* @param unknown_type $wipefirst
|
||||
*/
|
||||
public static function update_cm_from_form($cm,$fromform,$wipefirst=true) {
|
||||
$ci=new condition_info($cm,CONDITION_MISSING_EVERYTHING,false);
|
||||
if($wipefirst) {
|
||||
$ci->wipe_conditions();
|
||||
}
|
||||
foreach($fromform->conditiongradegroup as $record) {
|
||||
if($record['conditiongradeitemid']) {
|
||||
$ci->add_grade_condition($record['conditiongradeitemid'],
|
||||
$record['conditiongrademin'],$record['conditiongrademax']);
|
||||
}
|
||||
}
|
||||
if(isset($fromform->conditioncompletiongroup)) {
|
||||
foreach($fromform->conditioncompletiongroup as $record) {
|
||||
if($record['conditionsourcecmid']) {
|
||||
$ci->add_completion_condition($record['conditionsourcecmid'],
|
||||
$record['conditionrequiredcompletion']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
@ -1835,7 +1835,7 @@ function instance_is_visible($moduletype, $module) {
|
||||
* @return bool
|
||||
*/
|
||||
function coursemodule_visible_for_user($cm, $userid=0) {
|
||||
global $USER;
|
||||
global $USER,$CFG;
|
||||
|
||||
if (empty($cm->id)) {
|
||||
debugging("Incorrect course module parameter!", DEBUG_DEVELOPER);
|
||||
@ -1847,6 +1847,15 @@ function coursemodule_visible_for_user($cm, $userid=0) {
|
||||
if (!$cm->visible and !has_capability('moodle/course:viewhiddenactivities', get_context_instance(CONTEXT_MODULE, $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',
|
||||
get_context_instance(CONTEXT_MODULE, $cm->id), $userid)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return groups_course_module_visible($cm, $userid);
|
||||
}
|
||||
|
||||
|
@ -171,8 +171,8 @@
|
||||
<FIELD NAME="sourcecmid" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="If this condition is based on completion of another activity, then this is the course-module ID of that activity. Otherwise null." PREVIOUS="coursemoduleid" NEXT="requiredcompletion"/>
|
||||
<FIELD NAME="requiredcompletion" TYPE="int" LENGTH="1" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="If this condition is on a module's completion, then this should be set to the required completion state. Otherwise null. Suitable values are 1 = completed, 2 = completed-passed, 3 = completed-failed." PREVIOUS="sourcecmid" NEXT="gradeitemid"/>
|
||||
<FIELD NAME="gradeitemid" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="true" SEQUENCE="false" ENUM="false" COMMENT="If this condition is based on a gradebook score, the item ID is given here (and the item will now not be available until a value is achieved for that grade). Otherwise null." PREVIOUS="requiredcompletion" NEXT="grademin"/>
|
||||
<FIELD NAME="grademin" TYPE="number" LENGTH="10" NOTNULL="false" UNSIGNED="false" SEQUENCE="false" ENUM="false" DECIMALS="5" COMMENT="If set, this is the minimum grade that must be reached in order for this module to appear. Otherwise null." PREVIOUS="gradeitemid" NEXT="grademax"/>
|
||||
<FIELD NAME="grademax" TYPE="number" LENGTH="10" NOTNULL="false" UNSIGNED="false" SEQUENCE="false" ENUM="false" DECIMALS="5" COMMENT="If set, this is the maximum grade that can be reached in order to display this item. Otherwise null." PREVIOUS="grademin"/>
|
||||
<FIELD NAME="grademin" TYPE="number" LENGTH="10" NOTNULL="false" UNSIGNED="false" SEQUENCE="false" ENUM="false" DECIMALS="5" COMMENT="If set, this is the minimum grade that must be reached (greater than or equal) in order for this module to appear. Otherwise null." PREVIOUS="gradeitemid" NEXT="grademax"/>
|
||||
<FIELD NAME="grademax" TYPE="number" LENGTH="10" NOTNULL="false" UNSIGNED="false" SEQUENCE="false" ENUM="false" DECIMALS="5" COMMENT="If set, this is the maximum grade that users must be below (less than) in order to display this item. Otherwise null." PREVIOUS="grademin"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="coursemoduleid"/>
|
||||
|
@ -1056,60 +1056,6 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint($result, 2008111801);
|
||||
}
|
||||
|
||||
if ($result && $oldversion < 2008112400) {
|
||||
|
||||
/// Define field availablefrom to be added to course_modules
|
||||
$table = new xmldb_table('course_modules');
|
||||
$field = new xmldb_field('availablefrom', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'completionexpected');
|
||||
|
||||
/// Conditionally launch add field availablefrom
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
/// Define field availableuntil to be added to course_modules
|
||||
$field = new xmldb_field('availableuntil', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'availablefrom');
|
||||
|
||||
/// Conditionally launch add field availableuntil
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
/// Define field showavailability to be added to course_modules
|
||||
$field = new xmldb_field('showavailability', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'availableuntil');
|
||||
|
||||
/// Conditionally launch add field showavailability
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
/// Define table course_modules_availability to be created
|
||||
$table = new xmldb_table('course_modules_availability');
|
||||
|
||||
/// Adding fields to table course_modules_availability
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
|
||||
$table->add_field('coursemoduleid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
|
||||
$table->add_field('sourcecmid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
|
||||
$table->add_field('requiredcompletion', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, null, null, null, null, null);
|
||||
$table->add_field('gradeitemid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
|
||||
$table->add_field('grademin', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null, null, null);
|
||||
$table->add_field('grademax', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null, null, null);
|
||||
|
||||
/// Adding keys to table course_modules_availability
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$table->add_key('coursemoduleid', XMLDB_KEY_FOREIGN, array('coursemoduleid'), 'course_modules', array('id'));
|
||||
$table->add_key('sourcecmid', XMLDB_KEY_FOREIGN, array('sourcecmid'), 'course_modules', array('id'));
|
||||
$table->add_key('gradeitemid', XMLDB_KEY_FOREIGN, array('gradeitemid'), 'grade_items', array('id'));
|
||||
|
||||
/// Conditionally launch create table for course_modules_availability
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
/// Main savepoint reached
|
||||
upgrade_main_savepoint($result, 2008112400);
|
||||
}
|
||||
|
||||
if ($result && $oldversion < 2008120700) {
|
||||
|
||||
/// Changing precision of field shortname on table course_request to (100)
|
||||
@ -1155,6 +1101,70 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint($result, 2008120801);
|
||||
}
|
||||
|
||||
if ($result && $oldversion < 2008121701) {
|
||||
|
||||
/// Define field availablefrom to be added to course_modules
|
||||
$table = new xmldb_table('course_modules');
|
||||
$field = new xmldb_field('availablefrom', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'completionexpected');
|
||||
|
||||
/// Conditionally launch add field availablefrom
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
/// Define field availableuntil to be added to course_modules
|
||||
$field = new xmldb_field('availableuntil', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'availablefrom');
|
||||
|
||||
/// Conditionally launch add field availableuntil
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
/// Define field showavailability to be added to course_modules
|
||||
$field = new xmldb_field('showavailability', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'availableuntil');
|
||||
|
||||
/// Conditionally launch add field showavailability
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
/// Define table course_modules_availability to be created
|
||||
$table = new xmldb_table('course_modules_availability');
|
||||
|
||||
/// Adding fields to table course_modules_availability
|
||||
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null, null, null);
|
||||
$table->add_field('coursemoduleid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, null);
|
||||
$table->add_field('sourcecmid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
|
||||
$table->add_field('requiredcompletion', XMLDB_TYPE_INTEGER, '1', XMLDB_UNSIGNED, null, null, null, null, null);
|
||||
$table->add_field('gradeitemid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null, null, null);
|
||||
$table->add_field('grademin', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null, null, null);
|
||||
$table->add_field('grademax', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null, null, null);
|
||||
|
||||
/// Adding keys to table course_modules_availability
|
||||
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
|
||||
$table->add_key('coursemoduleid', XMLDB_KEY_FOREIGN, array('coursemoduleid'), 'course_modules', array('id'));
|
||||
$table->add_key('sourcecmid', XMLDB_KEY_FOREIGN, array('sourcecmid'), 'course_modules', array('id'));
|
||||
$table->add_key('gradeitemid', XMLDB_KEY_FOREIGN, array('gradeitemid'), 'grade_items', array('id'));
|
||||
|
||||
/// Conditionally launch create table for course_modules_availability
|
||||
if (!$dbman->table_exists($table)) {
|
||||
$dbman->create_table($table);
|
||||
}
|
||||
|
||||
/// Changes to modinfo mean we need to rebuild course cache
|
||||
rebuild_course_cache(0,true);
|
||||
|
||||
/// For developer upgrades, turn on the conditional activities and completion
|
||||
/// features automatically (to gain more testing)
|
||||
if(debugging('',DEBUG_DEVELOPER)) {
|
||||
set_config('enableavailability',1);
|
||||
set_config('enablecompletion',1);
|
||||
}
|
||||
|
||||
/// Main savepoint reached
|
||||
upgrade_main_savepoint($result, 2008121701);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -738,10 +738,16 @@ class grade_grade extends grade_object {
|
||||
|
||||
/**
|
||||
* Used to notify the completion system (if necessary) that a user's grade
|
||||
* has changed.
|
||||
* has changed, and clear up a possible score cache.
|
||||
* @param bool deleted True if grade was actually deleted
|
||||
*/
|
||||
function notify_changed($deleted) {
|
||||
// Grades may be cached in user session
|
||||
global $USER,$SESSION;
|
||||
if($USER->id==$this->userid) {
|
||||
unset($SESSION->gradescorecache[$this->itemid]);
|
||||
}
|
||||
|
||||
// Ignore during restore
|
||||
// TODO There should be a proper way to determine when we are in restore
|
||||
// so that this hack looking for a $restore global is not needed.
|
||||
|
@ -2047,6 +2047,30 @@ function require_login($courseorid=0, $autologinguest=true, $cm=null, $setwantsu
|
||||
print_error('nocontext');
|
||||
}
|
||||
}
|
||||
|
||||
// Conditional activity access control
|
||||
if(!empty($CFG->enableavailability) and $cm) {
|
||||
// We cache conditional access in session
|
||||
if(!isset($SESSION->conditionaccessok)) {
|
||||
$SESSION->conditionaccessok=array();
|
||||
}
|
||||
// If you have been allowed into the module once then you are allowed
|
||||
// in for rest of session, no need to do conditional checks
|
||||
if(!array_key_exists($cm->id,$SESSION->conditionaccessok)) {
|
||||
// Get condition info (does a query for the availability table)
|
||||
require_once($CFG->libdir.'/conditionlib.php');
|
||||
$ci=new condition_info($cm,CONDITION_MISSING_EXTRATABLE);
|
||||
// Check condition for user (this will do a query if the availability
|
||||
// information depends on grade or completion information)
|
||||
if($ci->is_available($junk) ||
|
||||
has_capability('moodle/course:viewhiddenactivities', $COURSE->context)) {
|
||||
$SESSION->conditionaccessok[$cm->id]=true;
|
||||
} else {
|
||||
print_error('activityiscurrentlyhidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($COURSE->id == SITEID) {
|
||||
/// Eliminate hidden site activities straight away
|
||||
if (!empty($cm) && !$cm->visible
|
||||
|
344
lib/simpletest/testconditionlib.php
Normal file
344
lib/simpletest/testconditionlib.php
Normal file
@ -0,0 +1,344 @@
|
||||
<?php
|
||||
if (!defined('MOODLE_INTERNAL')) {
|
||||
die('Direct access to this script is forbidden.');
|
||||
}
|
||||
|
||||
require_once($CFG->dirroot . '/lib/conditionlib.php');
|
||||
|
||||
class conditionlib_test extends MoodleUnitTestCase {
|
||||
var $oldcfg;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
global $CFG;
|
||||
$this->oldcfg=clone $CFG;
|
||||
$CFG->enableavailability=true;
|
||||
$CFG->enablecompletion=true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called after each test method. Doesn't do anything extraordinary except restore the global $DB to the real one.
|
||||
*/
|
||||
public function tearDown() {
|
||||
$CFG->enableavailability=$this->oldcfg->enableavailability;
|
||||
$CFG->enablecompletion=$this->oldcfg->enablecompletion;
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
function test_constructor() {
|
||||
global $DB,$CFG;
|
||||
$cm=new stdClass;
|
||||
|
||||
// Test records
|
||||
$id=$DB->insert_record('course_modules',(object)array(
|
||||
'showavailability'=>1,'availablefrom'=>17,'availableuntil'=>398,'course'=>64));
|
||||
|
||||
// no ID
|
||||
try {
|
||||
$test=new condition_info($cm);
|
||||
$this->fail();
|
||||
} catch(coding_exception $e) {
|
||||
}
|
||||
|
||||
// no other data
|
||||
$cm->id=$id;
|
||||
$test=new condition_info($cm,CONDITION_MISSING_EVERYTHING);
|
||||
$this->assertEqual(
|
||||
(object)array('id'=>$id,'showavailability'=>1,
|
||||
'availablefrom'=>17,'availableuntil'=>398,'course'=>64,
|
||||
'conditionsgrade'=>array(), 'conditionscompletion'=>array()),
|
||||
$test->get_full_course_module());
|
||||
|
||||
// just the course_modules stuff; check it doesn't request that from db
|
||||
$cm->showavailability=0;
|
||||
$cm->availablefrom=2;
|
||||
$cm->availableuntil=74;
|
||||
$cm->course=38;
|
||||
$test=new condition_info($cm,CONDITION_MISSING_EXTRATABLE);
|
||||
$this->assertEqual(
|
||||
(object)array('id'=>$id,'showavailability'=>0,
|
||||
'availablefrom'=>2,'availableuntil'=>74,'course'=>38,
|
||||
'conditionsgrade'=>array(), 'conditionscompletion'=>array()),
|
||||
$test->get_full_course_module());
|
||||
|
||||
// Now let's add some actual grade/completion conditions
|
||||
$DB->insert_record('course_modules_availability',(object)array(
|
||||
'coursemoduleid'=>$id,
|
||||
'sourcecmid'=>42,
|
||||
'requiredcompletion'=>2
|
||||
));
|
||||
$DB->insert_record('course_modules_availability',(object)array(
|
||||
'coursemoduleid'=>$id,
|
||||
'sourcecmid'=>666,
|
||||
'requiredcompletion'=>1
|
||||
));
|
||||
$DB->insert_record('course_modules_availability',(object)array(
|
||||
'coursemoduleid'=>$id,
|
||||
'gradeitemid'=>37,
|
||||
'grademin'=>5.5
|
||||
));
|
||||
|
||||
$cm=(object)array('id'=>$id);
|
||||
$test=new condition_info($cm,CONDITION_MISSING_EVERYTHING);
|
||||
$fullcm=$test->get_full_course_module();
|
||||
$this->assertEqual(array(42=>2,666=>1),$fullcm->conditionscompletion);
|
||||
$this->assertEqual(array(37=>(object)array('min'=>5.5,'max'=>null,'name'=>'!missing')),
|
||||
$fullcm->conditionsgrade);
|
||||
}
|
||||
|
||||
private function make_course() {
|
||||
global $DB;
|
||||
$categoryid=$DB->insert_record('course_categories',(object)array());
|
||||
return $DB->insert_record('course',(object)array(
|
||||
'fullname'=>'Condition test','shortname'=>'CT1',
|
||||
'category'=>$categoryid,'enablecompletion'=>1));
|
||||
}
|
||||
|
||||
private function make_course_module($courseid,$params=array()) {
|
||||
global $DB;
|
||||
static $moduleid=0;
|
||||
if(!$moduleid) {
|
||||
$moduleid=$DB->get_field('modules','id',array('name'=>'resource'));
|
||||
}
|
||||
|
||||
$rid=$DB->insert_record('resource',(object)array('course'=>$courseid,
|
||||
'name'=>'xxx','alltext'=>'','popup'=>''));
|
||||
$settings=(object)array(
|
||||
'course'=>$courseid,'module'=>$moduleid,'instance'=>$rid);
|
||||
foreach($params as $name=>$value) {
|
||||
$settings->{$name}=$value;
|
||||
}
|
||||
return $DB->insert_record('course_modules',$settings);
|
||||
}
|
||||
|
||||
private function make_section($courseid,$cmids,$sectionnum=0) {
|
||||
global $DB;
|
||||
$DB->insert_record('course_sections',(object)array(
|
||||
'course'=>$courseid,'sequence'=>implode(',',$cmids),'section'=>$sectionnum));
|
||||
}
|
||||
|
||||
function test_modinfo() {
|
||||
global $DB;
|
||||
|
||||
// Let's make a course
|
||||
$courseid=$this->make_course();
|
||||
|
||||
// Now let's make a couple modules on that course
|
||||
$cmid1=$this->make_course_module($courseid,array(
|
||||
'showavailability'=>1,'availablefrom'=>17,'availableuntil'=>398,
|
||||
'completion'=>COMPLETION_TRACKING_MANUAL));
|
||||
$cmid2=$this->make_course_module($courseid,array(
|
||||
'showavailability'=>0,'availablefrom'=>0,'availableuntil'=>0));
|
||||
$this->make_section($courseid,array($cmid1,$cmid2));
|
||||
|
||||
// Add a fake grade item
|
||||
$gradeitemid=$DB->insert_record('grade_items',(object)array(
|
||||
'courseid'=>$courseid,'itemname'=>'frog'));
|
||||
|
||||
// One of the modules has grade and completion conditions, other doesn't
|
||||
$DB->insert_record('course_modules_availability',(object)array(
|
||||
'coursemoduleid'=>$cmid2,
|
||||
'sourcecmid'=>$cmid1,
|
||||
'requiredcompletion'=>1
|
||||
));
|
||||
$DB->insert_record('course_modules_availability',(object)array(
|
||||
'coursemoduleid'=>$cmid2,
|
||||
'gradeitemid'=>$gradeitemid,
|
||||
'grademin'=>5.5
|
||||
));
|
||||
|
||||
// Okay sweet, now get modinfo
|
||||
$modinfo=get_fast_modinfo($DB->get_record('course',array('id'=>$courseid)));
|
||||
|
||||
// Test basic data
|
||||
$this->assertEqual(1,$modinfo->cms[$cmid1]->showavailability);
|
||||
$this->assertEqual(17,$modinfo->cms[$cmid1]->availablefrom);
|
||||
$this->assertEqual(398,$modinfo->cms[$cmid1]->availableuntil);
|
||||
$this->assertEqual(0,$modinfo->cms[$cmid2]->showavailability);
|
||||
$this->assertEqual(0,$modinfo->cms[$cmid2]->availablefrom);
|
||||
$this->assertEqual(0,$modinfo->cms[$cmid2]->availableuntil);
|
||||
|
||||
// Test condition arrays
|
||||
$this->assertEqual(array(),$modinfo->cms[$cmid1]->conditionscompletion);
|
||||
$this->assertEqual(array(),$modinfo->cms[$cmid1]->conditionsgrade);
|
||||
$this->assertEqual(array($cmid1=>1),
|
||||
$modinfo->cms[$cmid2]->conditionscompletion);
|
||||
$this->assertEqual(array($gradeitemid=>(object)array('min'=>5.5,'max'=>null,'name'=>'frog')),
|
||||
$modinfo->cms[$cmid2]->conditionsgrade);
|
||||
}
|
||||
|
||||
function test_add_and_remove() {
|
||||
global $DB;
|
||||
// Make course and module
|
||||
$courseid=$this->make_course();
|
||||
$cmid=$this->make_course_module($courseid,array(
|
||||
'showavailability'=>0,'availablefrom'=>0,'availableuntil'=>0));
|
||||
$this->make_section($courseid,array($cmid));
|
||||
|
||||
// Check it has no conditions
|
||||
$test1=new condition_info((object)array('id'=>$cmid),
|
||||
CONDITION_MISSING_EVERYTHING);
|
||||
$cm=$test1->get_full_course_module();
|
||||
$this->assertEqual(array(),$cm->conditionscompletion);
|
||||
$this->assertEqual(array(),$cm->conditionsgrade);
|
||||
|
||||
// Add conditions of each type
|
||||
$test1->add_completion_condition(13,3);
|
||||
$this->assertEqual(array(13=>3),$cm->conditionscompletion);
|
||||
$test1->add_grade_condition(666,0.4,null,true);
|
||||
$this->assertEqual(array(666=>(object)array('min'=>0.4,'max'=>null,'name'=>'!missing')),
|
||||
$cm->conditionsgrade);
|
||||
|
||||
// Check they were really added in db
|
||||
$test2=new condition_info((object)array('id'=>$cmid),
|
||||
CONDITION_MISSING_EVERYTHING);
|
||||
$cm=$test2->get_full_course_module();
|
||||
$this->assertEqual(array(13=>3),$cm->conditionscompletion);
|
||||
$this->assertEqual(array(666=>(object)array('min'=>0.4,'max'=>null,'name'=>'!missing')),
|
||||
$cm->conditionsgrade);
|
||||
|
||||
// Wipe conditions
|
||||
$test2->wipe_conditions();
|
||||
$this->assertEqual(array(),$cm->conditionscompletion);
|
||||
$this->assertEqual(array(),$cm->conditionsgrade);
|
||||
|
||||
// Check they were really wiped
|
||||
$test3=new condition_info((object)array('id'=>$cmid),
|
||||
CONDITION_MISSING_EVERYTHING);
|
||||
$cm=$test3->get_full_course_module();
|
||||
$this->assertEqual(array(),$cm->conditionscompletion);
|
||||
$this->assertEqual(array(),$cm->conditionsgrade);
|
||||
}
|
||||
|
||||
function test_is_available() {
|
||||
global $DB,$USER;
|
||||
$courseid=$this->make_course();
|
||||
|
||||
// No conditions
|
||||
$cmid=$this->make_course_module($courseid);
|
||||
$ci=new condition_info((object)array('id'=>$cmid),
|
||||
CONDITION_MISSING_EVERYTHING);
|
||||
$this->assertTrue($ci->is_available($text,false,0));
|
||||
$this->assertEqual('',$text);
|
||||
|
||||
// Time (from)
|
||||
$time=time()+100;
|
||||
$cmid=$this->make_course_module($courseid,array('availablefrom'=>$time));
|
||||
$ci=new condition_info((object)array('id'=>$cmid),
|
||||
CONDITION_MISSING_EVERYTHING);
|
||||
$this->assertFalse($ci->is_available($text));
|
||||
$this->assert(new PatternExpectation(
|
||||
'/'.preg_quote(userdate($time,get_string('strftimedate','langconfig'))).'/'),$text);
|
||||
|
||||
$time=time()-100;
|
||||
$cmid=$this->make_course_module($courseid,array('availablefrom'=>$time));
|
||||
$ci=new condition_info((object)array('id'=>$cmid),
|
||||
CONDITION_MISSING_EVERYTHING);
|
||||
$this->assertTrue($ci->is_available($text));
|
||||
$this->assertEqual('',$text);
|
||||
$this->assert(new PatternExpectation(
|
||||
'/'.preg_quote(userdate($time,get_string('strftimedate','langconfig'))).'/'),$ci->get_full_information());
|
||||
|
||||
// Time (until)
|
||||
$cmid=$this->make_course_module($courseid,array('availableuntil'=>time()-100));
|
||||
$ci=new condition_info((object)array('id'=>$cmid),
|
||||
CONDITION_MISSING_EVERYTHING);
|
||||
$this->assertFalse($ci->is_available($text));
|
||||
$this->assertEqual('',$text);
|
||||
|
||||
// Completion
|
||||
$oldid=$cmid;
|
||||
$cmid=$this->make_course_module($courseid);
|
||||
$this->make_section($courseid,array($oldid,$cmid));
|
||||
$oldcm=$DB->get_record('course_modules',array('id'=>$oldid));
|
||||
$oldcm->completion=COMPLETION_TRACKING_MANUAL;
|
||||
$DB->update_record('course_modules',$oldcm);
|
||||
|
||||
$ci=new condition_info((object)array('id'=>$cmid),CONDITION_MISSING_EVERYTHING);
|
||||
$ci->add_completion_condition($oldid,COMPLETION_COMPLETE);
|
||||
$this->assertFalse($ci->is_available($text,false));
|
||||
$this->assertEqual(get_string('requires_completion_1','condition','xxx'),$text);
|
||||
|
||||
$completion=new completion_info($DB->get_record('course',array('id'=>$courseid)));
|
||||
$completion->update_state($oldcm,COMPLETION_COMPLETE);
|
||||
completion_info::wipe_session_cache();
|
||||
condition_info::wipe_session_cache();
|
||||
|
||||
$this->assertTrue($ci->is_available($text));
|
||||
$this->assertFalse($ci->is_available($text,false,$USER->id+1));
|
||||
completion_info::wipe_session_cache();
|
||||
condition_info::wipe_session_cache();
|
||||
$completion=new completion_info($DB->get_record('course',array('id'=>$courseid)));
|
||||
$completion->update_state($oldcm,COMPLETION_INCOMPLETE);
|
||||
$this->assertFalse($ci->is_available($text));
|
||||
|
||||
$ci->wipe_conditions();
|
||||
$ci->add_completion_condition($oldid,COMPLETION_INCOMPLETE);
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertTrue($ci->is_available($text));
|
||||
$this->assertTrue($ci->is_available($text,false,$USER->id+1));
|
||||
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertTrue($ci->is_available($text,true));
|
||||
|
||||
// Grade
|
||||
$ci->wipe_conditions();
|
||||
// Add a fake grade item
|
||||
$gradeitemid=$DB->insert_record('grade_items',(object)array(
|
||||
'courseid'=>$courseid,'itemname'=>'frog'));
|
||||
// Add a condition on a value existing...
|
||||
$ci->add_grade_condition($gradeitemid,null,null,true);
|
||||
$this->assertFalse($ci->is_available($text));
|
||||
$this->assertEqual(get_string('requires_grade_any','condition','frog'),$text);
|
||||
|
||||
// Fake it existing
|
||||
$DB->insert_record('grade_grades',(object)array(
|
||||
'itemid'=>$gradeitemid,'userid'=>$USER->id,'finalgrade'=>3.78));
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertTrue($ci->is_available($text));
|
||||
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertTrue($ci->is_available($text,true));
|
||||
|
||||
// Now require that user gets more than 3.78001
|
||||
$ci->wipe_conditions();
|
||||
$ci->add_grade_condition($gradeitemid,3.78001,null,true);
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertFalse($ci->is_available($text));
|
||||
$this->assertEqual(get_string('requires_grade_min','condition','frog'),$text);
|
||||
|
||||
// ...just on 3.78...
|
||||
$ci->wipe_conditions();
|
||||
$ci->add_grade_condition($gradeitemid,3.78,null,true);
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertTrue($ci->is_available($text));
|
||||
|
||||
// ...less than 3.78
|
||||
$ci->wipe_conditions();
|
||||
$ci->add_grade_condition($gradeitemid,null,3.78,true);
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertFalse($ci->is_available($text));
|
||||
$this->assertEqual(get_string('requires_grade_max','condition','frog'),$text);
|
||||
|
||||
// ...less than 3.78001
|
||||
$ci->wipe_conditions();
|
||||
$ci->add_grade_condition($gradeitemid,null,3.78001,true);
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertTrue($ci->is_available($text));
|
||||
|
||||
// ...in a range that includes it
|
||||
$ci->wipe_conditions();
|
||||
$ci->add_grade_condition($gradeitemid,3,4,true);
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertTrue($ci->is_available($text));
|
||||
|
||||
// ...in a range that doesn't include it
|
||||
$ci->wipe_conditions();
|
||||
$ci->add_grade_condition($gradeitemid,4,5,true);
|
||||
condition_info::wipe_session_cache();
|
||||
$this->assertFalse($ci->is_available($text));
|
||||
$this->assertEqual(get_string('requires_grade_range','condition','frog'),$text);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
@ -569,6 +569,19 @@ h2.headingblock {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
#course-view .availabilityinfo {
|
||||
font-size:0.85em;
|
||||
color:#aaa;
|
||||
}
|
||||
#course-view .availabilityinfo strong {
|
||||
font-weight:normal;
|
||||
color:black;
|
||||
}
|
||||
#course-view .dimmed_text img {
|
||||
opacity:0.3;
|
||||
filter: alpha(opacity='30');
|
||||
}
|
||||
|
||||
/***
|
||||
*** Doc
|
||||
***/
|
||||
@ -1057,6 +1070,10 @@ body#mod-forum-index .generalbox .cell {
|
||||
#mod-quiz-edit .questionbankwindow div.header{
|
||||
font-weight:bold;
|
||||
}
|
||||
#mod-quiz-edit a.configurerandomquestion{
|
||||
font-size:small;
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
|
@ -6,7 +6,7 @@
|
||||
// This is compared against the values stored in the database to determine
|
||||
// whether upgrades should be performed (see lib/db/*.php)
|
||||
|
||||
$version = 2008121000; // YYYYMMDD = date of the last version bump
|
||||
$version = 2008121701; // YYYYMMDD = date of the last version bump
|
||||
// XX = daily increments
|
||||
|
||||
$release = '2.0 dev (Build: 20081217)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user