diff --git a/mod/scorm/classes/task/update_grades.php b/mod/scorm/classes/task/update_grades.php new file mode 100644 index 00000000000..3e196e137a0 --- /dev/null +++ b/mod/scorm/classes/task/update_grades.php @@ -0,0 +1,37 @@ +. + +namespace mod_scorm\task; + +/** + * Adhoc task for recalculating grades. + * + * @package mod_scorm + * @copyright 2022 Dan Marsden + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class update_grades extends \core\task\adhoc_task { + /** + * Execute task. + */ + public function execute() { + global $CFG, $DB; + require_once($CFG->dirroot.'/mod/scorm/locallib.php'); + $data = $this->get_custom_data(); + $scorm = $DB->get_record('scorm', ['id' => $data->scormid]); + scorm_update_grades($scorm, $data->userid); + } +} diff --git a/mod/scorm/db/upgrade.php b/mod/scorm/db/upgrade.php index 397b00a79ec..dd08a68a0f3 100644 --- a/mod/scorm/db/upgrade.php +++ b/mod/scorm/db/upgrade.php @@ -171,5 +171,40 @@ function xmldb_scorm_upgrade($oldversion) { // Automatically generated Moodle v4.3.0 release upgrade line. // Put any upgrade step following this. + if ($oldversion < 2023100901) { + // MDL-76697 - fix up any possible activity completion states since the upgrade to 2023042403. + // Get timestamp of when this site updated to version 2023042403. + $upgraded = $DB->get_field_sql("SELECT min(timemodified) + FROM {upgrade_log} + WHERE plugin = 'mod_scorm' AND version = '2023042403'"); + if (empty($upgraded)) { + // The code causing this regression landed upstream 28 Jul 2023, if a site has done a fresh install since then, + // the upgrade step won't exist - set it to 20th July so we don't end up dealing with too many attempts. + $upgraded = 1689811200; // 20 July 2023 12AM + } + // Don't bother triggering this next step if the upgrade completed within the last hour. + if (time() - HOURSECS > $upgraded) { + // Get all attempts that have occurred since the upgrade. + $sql = "SELECT DISTINCT s.*, sa.userid + FROM {scorm} s + JOIN {scorm_attempt} sa ON sa.scormid = s.id + JOIN {scorm_scoes_value} sv on sv.attemptid = sa.id + WHERE sv.timemodified > ?"; + $scorms = $DB->get_recordset_sql($sql, [$upgraded]); + foreach ($scorms as $scorm) { + // Run an ad-hoc task to update the grades. + $task = new \mod_scorm\task\update_grades(); + $task->set_custom_data([ + 'scormid' => $scorm->id, + 'userid' => $scorm->userid, + ]); + \core\task\manager::queue_adhoc_task($task, true); + } + $scorms->close(); + } + + // Scorm savepoint reached. + upgrade_mod_savepoint(true, 2023100901, 'scorm'); + } return true; } diff --git a/mod/scorm/locallib.php b/mod/scorm/locallib.php index af82cf20aa6..a6072de5417 100644 --- a/mod/scorm/locallib.php +++ b/mod/scorm/locallib.php @@ -559,28 +559,27 @@ function scorm_insert_track($userid, $scormid, $scoid, $attemptornumber, $elemen // Trigger updating grades based on a given set of SCORM CMI elements. $scorm = false; - if (in_array($element, array('cmi.core.score.raw', 'cmi.score.raw')) || - (in_array($element, array('cmi.completion_status', 'cmi.core.lesson_status', 'cmi.success_status')) - && in_array($track->value, array('completed', 'passed')))) { + if (in_array($element, ['cmi.core.score.raw', 'cmi.score.raw']) || + (in_array($element, ['cmi.completion_status', 'cmi.core.lesson_status', 'cmi.success_status']) + && in_array($value, ['completed', 'passed']))) { $scorm = $DB->get_record('scorm', array('id' => $scormid)); include_once($CFG->dirroot.'/mod/scorm/lib.php'); scorm_update_grades($scorm, $userid); } // Trigger CMI element events. - if (in_array($element, array('cmi.core.score.raw', 'cmi.score.raw')) || - (in_array($element, array('cmi.completion_status', 'cmi.core.lesson_status', 'cmi.success_status')) - && in_array($track->value, array('completed', 'failed', 'passed')))) { + if (in_array($element, ['cmi.core.score.raw', 'cmi.score.raw']) || + (in_array($element, ['cmi.completion_status', 'cmi.core.lesson_status', 'cmi.success_status']) + && in_array($value, ['completed', 'failed', 'passed']))) { if (!$scorm) { $scorm = $DB->get_record('scorm', array('id' => $scormid)); } $cm = get_coursemodule_from_instance('scorm', $scormid); - $data = array( - 'other' => array('attemptid' => $attempt->id, 'cmielement' => $element, 'cmivalue' => $track->value), - 'objectid' => $scorm->id, - 'context' => context_module::instance($cm->id), - 'relateduserid' => $userid - ); + $data = ['other' => ['attemptid' => $attempt->id, 'cmielement' => $element, 'cmivalue' => $value], + 'objectid' => $scorm->id, + 'context' => context_module::instance($cm->id), + 'relateduserid' => $userid, + ]; if (in_array($element, array('cmi.core.score.raw', 'cmi.score.raw'))) { // Create score submitted event. $event = \mod_scorm\event\scoreraw_submitted::create($data); @@ -590,9 +589,10 @@ function scorm_insert_track($userid, $scormid, $scoid, $attemptornumber, $elemen } // Fix the missing track keys when the SCORM track record already exists, see $trackdata in datamodel.php. // There, for performances reasons, columns are limited to: element, id, value, timemodified. - // Missing fields are: scoid, attempt. + // Missing fields are: scoid, attemptid, elementid. $track->scoid = $scoid; - $track->attempt = $attempt->id; + $track->attemptid = $attempt->id; + $track->elementid = scorm_get_elementid($element); $track->id = $id; // Trigger submitted event. $event->add_record_snapshot('scorm_scoes_value', $track); diff --git a/mod/scorm/version.php b/mod/scorm/version.php index d178e8b6a36..15146218d77 100644 --- a/mod/scorm/version.php +++ b/mod/scorm/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2023100900; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2023100901; // The current module version (Date: YYYYMMDDXX). $plugin->requires = 2023100400; // Requires this Moodle version. $plugin->component = 'mod_scorm'; // Full name of the plugin (used for diagnostics).