Commit 9da95f78 authored by Astor Bizard's avatar Astor Bizard 🐕
Browse files

Added support for completion tracking of assigned activities.

parent 2eec2403
......@@ -15,7 +15,7 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Observer for grade and grade items changes in other activities.
* Observer for grade, grade items and completion changes in other activities.
* @package mod_randomactivity
* @copyright Astor Bizard, 2020
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
......@@ -29,11 +29,11 @@ require_once($CFG->dirroot . '/mod/randomactivity/locallib.php');
require_once($CFG->dirroot . '/mod/randomactivity/lib.php');
/**
* Grade observer definition.
* Module observer definition.
* @copyright Astor Bizard, 2020
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class grade_observer {
class module_observer {
/**
* Observer called every time an activity grade or grade item changes.
* Updates Random activities grades and grade items accordingly.
......@@ -43,19 +43,70 @@ class grade_observer {
global $DB;
$grade = $event->get_grade();
$gradeitem = $grade->grade_item;
if ($gradeitem->itemtype != 'mod' || $gradeitem->itemmodule == 'randomactivity') {
// Do not reflect grades of other randomactivities to avoid inifinite recursion.
// Such recursion is not supposed to happen anyway.
return;
}
$courseid = $gradeitem->courseid;
$userid = $grade->userid;
if ($gradeitem->itemtype == 'mod' && $gradeitem->itemmodule != 'randomactivity') {
$randomactivities = get_fast_modinfo($courseid, -1)->get_instances_of('randomactivity');
$gradedcm = get_fast_modinfo($courseid, -1)->get_instances_of($gradeitem->itemmodule)[$gradeitem->iteminstance];
foreach ($randomactivities as $cminfo) {
$modinstance = $DB->get_record('randomactivity', array( 'id' => $cminfo->instance ));
if ($modinstance->grade != 0 && ($modinstance->duedate == 0 || $modinstance->duedate >= time())) {
$cmid = randomactivity_get_assigned_activity($cminfo, $modinstance->activities, $userid, $modinstance->seed);
if ($cmid == $gradedcm->id) {
randomactivity_update_grade($modinstance, $userid, $grade);
}
$randomactivities = get_fast_modinfo($courseid, -1)->get_instances_of('randomactivity');
$gradedcm = get_fast_modinfo($courseid, -1)->get_instances_of($gradeitem->itemmodule)[$gradeitem->iteminstance];
foreach ($randomactivities as $ra) {
$modinstance = $DB->get_record('randomactivity', array('id' => $ra->instance));
if ($modinstance->grade != 0 && ($modinstance->duedate == 0 || $modinstance->duedate >= time())) {
$assignedcmid = randomactivity_get_assigned_activity($ra, $modinstance->activities, $userid, $modinstance->seed);
if ($assignedcmid == $gradedcm->id) {
// This Random activity has the graded module in its pool. User should have its grade updated.
randomactivity_update_grade($modinstance, $userid, $grade);
}
}
}
}
/**
* Observer called every time an activity completion is updated.
* Updates Random activities completion accordingly.
* @param \core\event\course_module_completion_updated $event
*/
public static function user_activity_completion_updated(\core\event\course_module_completion_updated $event) {
global $DB;
$eventdata = $event->get_record_snapshot('course_modules_completion', $event->objectid);
$userid = $event->relateduserid;
$module = get_coursemodule_from_id(null, $eventdata->coursemoduleid);
$course = get_course($module->course);
$courseinfo = get_fast_modinfo($course, $userid);
$completedcm = $courseinfo->get_cm($module->id);
if ($completedcm->modname == 'randomactivity') {
// Do not reflect completion of other randomactivities to avoid inifinite recursion.
// Such recursion is not supposed to happen anyway.
return;
}
$completion = new \completion_info($course);
if (!$completion->is_enabled()) {
return;
}
$randomactivities = $courseinfo->get_instances_of('randomactivity');
foreach ($randomactivities as $ra) {
if ($ra->completion != COMPLETION_TRACKING_AUTOMATIC ||
($ra->completionexpected > 0 && $ra->completionexpected < time())) {
continue;
}
$modinstance = $DB->get_record('randomactivity', array('id' => $ra->instance));
if ($modinstance->completiontrackactivity && ($modinstance->duedate == 0 || $modinstance->duedate >= time())) {
$assignedcmid = randomactivity_get_assigned_activity($ra, $modinstance->activities, $userid, $modinstance->seed);
if ($assignedcmid == $completedcm->id) {
// This Random activity has the completed module in its pool. User should have its completion updated.
// Calling update_state with COMPLETION_UNKNOWN will call randomactivity_get_completion_state.
$completion->update_state($ra, COMPLETION_UNKNOWN, $userid);
}
}
}
......
......@@ -26,6 +26,10 @@ defined('MOODLE_INTERNAL') || die();
$observers = array(
array(
'eventname' => '\core\event\user_graded',
'callback' => '\mod_randomactivity\grade_observer::user_activity_graded',
'callback' => '\mod_randomactivity\module_observer::user_activity_graded',
),
array(
'eventname' => '\core\event\course_module_completion_updated',
'callback' => '\mod_randomactivity\module_observer::user_activity_completion_updated',
)
);
......@@ -14,6 +14,7 @@
<FIELD NAME="seed" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Seed for random."/>
<FIELD NAME="dynamicdisplay" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Whether this activity instance should be displayed on course page as the activity it points to for students."/>
<FIELD NAME="grade" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Grade or scaleid."/>
<FIELD NAME="completiontrackactivity" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Whether this activity instance should automatically update its completion according to linked activities."/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time this activity instance was last modified."/>
</FIELDS>
<KEYS>
......
......@@ -60,5 +60,20 @@ function xmldb_randomactivity_upgrade($oldversion) {
upgrade_mod_savepoint(true, 2021052100, 'randomactivity');
}
if ($oldversion < 2022071300) {
$table = new xmldb_table('randomactivity');
// Define field completiontrackactivity to be added to randomactivity.
$field = new xmldb_field('completiontrackactivity', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, 0, 'grade');
// Conditionally launch add field completiontrackactivity.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Random activity savepoint reached.
upgrade_mod_savepoint(true, 2022071300, 'randomactivity');
}
return true;
}
......@@ -46,6 +46,10 @@ $string['applychangesreassign'] = 'Apply changes and re-assign';
$string['assignedactivity'] = 'Assigned activity';
$string['assignees'] = 'Assignees';
$string['changesapplied'] = 'Changes have been applied.';
$string['completiontrackactivity'] = 'Require assigned activity completion';
$string['completiontrackactivity_desc'] = 'Students must complete their assigned activity';
$string['completiontrackactivity_help'] = 'If enabled, this Random Activity will attempt to track completion of assigned activities and automatically update its completion accordingly.<br>
<b>Note:</b> This may override some of the other completion tracking methods.';
$string['confirmreassign'] = 'You are about to change the pool of activities used by this Random activity. Students will be re-assigned to new activities.<br>
Students who started working on their previously assigned activity will lose their progress if they are assigned to an other one.<br>
Students who earned a grade for their previously assigned activity will lose their grade for this activity if they are assigned to an other one.';
......
......@@ -132,6 +132,8 @@ function randomactivity_supports($feature) {
return true;
case FEATURE_BACKUP_MOODLE2 :
return true;
case FEATURE_COMPLETION_HAS_RULES:
return true;
default:
return null;
}
......@@ -423,3 +425,38 @@ function mod_randomactivity_core_calendar_provide_event_action(calendar_event $e
$event->timestart >= time()
);
}
/**
* Obtains the automatic completion state for this random activity.
*
* @param object $course Course
* @param object $module Course-module
* @param int $userid User ID
* @param bool $type Type of comparison (or/and; can be used as return value if no conditions)
* @return bool True if completed, false if not. (If no conditions, then return
* value depends on comparison type)
*/
function randomactivity_get_completion_state($course, $module, $userid, $type) {
global $DB;
$courseinfo = get_fast_modinfo($course, $userid);
$cm = $courseinfo->get_cm($module->id);
$modinstance = $DB->get_record('randomactivity', array('id' => $cm->instance), '*', MUST_EXIST);
$completion = new completion_info($course);
if (!$completion->is_enabled() || $cm->completion != COMPLETION_TRACKING_AUTOMATIC || !$modinstance->completiontrackactivity) {
return $type;
}
$relatedcmid = randomactivity_get_assigned_activity($cm, $modinstance->activities, $userid, $modinstance->seed);
$relatedcm = $courseinfo->get_cm($relatedcmid);
switch ($completion->get_data($relatedcm, false, $userid)->completionstate) {
case COMPLETION_COMPLETE:
case COMPLETION_COMPLETE_PASS:
return true;
case COMPLETION_INCOMPLETE:
case COMPLETION_COMPLETE_FAIL:
return false;
}
return $type;
}
......@@ -59,8 +59,32 @@ class mod_randomactivity_mod_form extends moodleform_mod {
$mform->setDefault( 'duedate', 0 );
$this->standard_grading_coursemodule_elements();
$this->standard_coursemodule_elements();
$this->add_action_buttons();
}
/**
* Add module-specific activity completion rules.
* @return array Array of string IDs of added items.
*/
public function add_completion_rules() {
$mform =& $this->_form;
$mform->addElement('advcheckbox', 'completiontrackactivity', get_string('completiontrackactivity', 'mod_randomactivity'),
get_string('completiontrackactivity_desc', 'mod_randomactivity'));
$mform->addHelpButton('completiontrackactivity', 'completiontrackactivity', 'mod_randomactivity');
return array('completiontrackactivity');
}
/**
* Called during validation. Indicates whether a module-specific completion rule is selected.
*
* @param array $data Input data (not yet validated)
* @return bool True if one or more rules is enabled, false if none are.
*/
public function completion_rule_enabled($data) {
return !empty($data['completiontrackactivity']);
}
}
......@@ -23,8 +23,8 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2022021803;
$plugin->version = 2022071300;
$plugin->requires = 2018112800;
$plugin->maturity = MATURITY_STABLE;
$plugin->release = '1.4.3';
$plugin->release = '1.5.0';
$plugin->component = 'mod_randomactivity';
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment