Skip to content

Commit

Permalink
Update SCORM reset & backup for 4.3 structure.
Browse files Browse the repository at this point in the history
  • Loading branch information
joshwillcock committed Jan 23, 2024
1 parent 9489d6d commit 4d30b3e
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 44 deletions.
20 changes: 15 additions & 5 deletions backup/moodle2/backup_local_recompletion_plugin.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,20 +116,30 @@ protected function define_course_plugin_structure() {
$grade->annotate_ids('user', 'userid');

// Now deal with SCORM archive tables.
$scormattempts = new backup_nested_element('scormattempts');

$scormattempt = new backup_nested_element('scormattempt', array('id'), array(
'scormid', 'userid', 'attempt', 'courseid'));

$recompletion->add_child($scormattempts);
$scormattempts->add_child($scormattempt);

if ($usercompletion) {
$scormattempt->set_source_table('local_recompletion_sa', array('courseid' => backup::VAR_COURSEID));
}
$scormattempt->annotate_ids('user', 'userid');

$scotracks = new backup_nested_element('scormtracks');

$scotrack = new backup_nested_element('sco_track', array('id'), array(
'userid', 'attempt', 'element', 'value',
'timemodified', 'course', 'scormid', 'scoid'));
'scoid', 'attemptid', 'elementid', 'value', 'courseid', 'timemodified'));

$recompletion->add_child($scotracks);
$scotracks->add_child($scotrack);

if ($usercompletion) {
$scotrack->set_source_table('local_recompletion_sst', array('course' => backup::VAR_COURSEID));
$scotrack->set_source_table('local_recompletion_ssv', array('courseid' => backup::VAR_COURSEID));
}
$scotrack->annotate_ids('user', 'userid');

// Now deal with choice archive tables.
$choiceanswers = new backup_nested_element('choiceanswers');

Expand Down
29 changes: 21 additions & 8 deletions backup/moodle2/restore_local_recompletion_plugin.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ protected function define_course_plugin_structure() {
$paths[] = new restore_path_element('recompletion_completion', $elepath.'/course_completion/completions/completion');
$paths[] = new restore_path_element('recompletion_qa', $elepath.'/quizattempts/attempt');
$paths[] = new restore_path_element('recompletion_qg', $elepath.'/quizgrades/grade');
$paths[] = new restore_path_element('recompletion_sst', $elepath.'/scormtracks/sco_track');
$paths[] = new restore_path_element('recompletion_sa', $elepath.'/scormattempts/scormattempt');
$paths[] = new restore_path_element('recompletion_ssv', $elepath.'/scormtracks/sco_track');
$paths[] = new restore_path_element('recompletion_cha', $elepath.'/choiceanswers/choiceanswer');
$paths[] = new restore_path_element('recompletion_hvp', $elepath.'/hvpattempts/hvpattempt');
$paths[] = new restore_path_element('recompletion_h5p', $elepath.'/h5ps/h5p');
Expand Down Expand Up @@ -147,17 +148,30 @@ public function process_recompletion_qg($data) {
}

/**
* Process local_recompletion_sst table.
* Process local_recompletion_sa table.
* @param stdClass $data
*/
public function process_recompletion_sst($data) {
public function process_recompletion_sa($data) {
global $DB;

$data = (object) $data;
$data->course = $this->task->get_courseid();
$data->courseid = $this->task->get_courseid();
$data->userid = $this->get_mappingid('user', $data->userid);

$DB->insert_record('local_recompletion_sst', $data);
$DB->insert_record('local_recompletion_sa', $data);
}

/**
* Process local_recompletion_sst table.
* @param stdClass $data
*/
public function process_recompletion_ssv($data) {
global $DB;

$data = (object) $data;
$data->courseid = $this->task->get_courseid();

$DB->insert_record('local_recompletion_ssv', $data);
}

/**
Expand Down Expand Up @@ -339,11 +353,10 @@ protected function after_restore_course() {
$rcm->close();

// Fix SCORM tracks.
$rcm = $DB->get_recordset('local_recompletion_sst', array('course' => $this->task->get_courseid()));
$rcm = $DB->get_recordset('local_recompletion_sa', array('courseid' => $this->task->get_courseid()));
foreach ($rcm as $rc) {
$rc->scormid = $this->get_mappingid('scorm', $rc->scormid);
$rc->scoid = $this->get_mappingid('scorm_sco', $rc->scoid);
$DB->update_record('local_recompletion_sst', $rc);
$DB->update_record('local_recompletion_sa', $rc);
}
$rcm->close();

Expand Down
26 changes: 18 additions & 8 deletions classes/plugins/mod_scorm.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,26 @@ public static function reset($userid, $course, $config) {
} else if ($config->scorm == LOCAL_RECOMPLETION_DELETE) {
$params = array('userid' => $userid, 'course' => $course->id);
$selectsql = 'userid = ? AND scormid IN (SELECT id FROM {scorm} WHERE course = ?)';
if ($config->archivescorm) {
$scormscoestrack = $DB->get_records_select('scorm_scoes_track', $selectsql, $params);
// Strictly not part of #78 but eliminates unused local variable violation.
foreach (array_keys($scormscoestrack) as $sid) {
// Add courseid to records to help with restore process.
$scormscoestrack[$sid]->course = $course->id;

$scormattempt = $DB->get_records_select('scorm_attempt', $selectsql, $params);
// Strictly not part of #78 but eliminates unused local variable violation.
foreach (array_keys($scormattempt) as $sid) {
// Add courseid to records to help with restore process.
$scormattempt[$sid]->courseid = $course->id;
$scormscoesvalue = $DB->get_records('scorm_scoes_value', ['attemptid' => $sid]);
if ($config->archivescorm) {
foreach (array_keys($scormscoesvalue) as $ssvid) {
$scormscoesvalue[$ssvid]->courseid = $course->id;

}
$DB->insert_records('local_recompletion_ssv', $scormscoesvalue);
}
$DB->insert_records('local_recompletion_sst', $scormscoestrack);
$DB->delete_records('scorm_scoes_value', ['attemptid' => $sid]);
}
if ($config->archivescorm) {
$DB->insert_records('local_recompletion_sa', $scormattempt);
}
$DB->delete_records_select('scorm_scoes_track', $selectsql, $params);
$DB->delete_records_select('scorm_attempt', $selectsql, $params);
$DB->delete_records_select('scorm_aicc_session', $selectsql, $params);
}
}
Expand Down
19 changes: 13 additions & 6 deletions classes/privacy/provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,20 @@ public static function get_metadata(collection $collection) : collection {
'timemodified' => 'privacy:metadata:quiz_grades:timemodified',
], 'privacy:metadata:quiz_grades');

$collection->add_database_table('local_recompletion_sst', [
$collection->add_database_table('local_recompletion_sa', [
'userid' => 'privacy:metadata:userid',
'attempt' => 'privacy:metadata:attempt',
'element' => 'privacy:metadata:scoes_track:element',
'value' => 'privacy:metadata:scoes_track:value',
'timemodified' => 'privacy:metadata:timemodified'
], 'privacy:metadata:scorm_scoes_track');
'scormid' => 'privacy:metadata:scormid',
'courseid' => 'privacy:metadata:course',
], 'privacy:metadata:scorm_attempt');

$collection->add_database_table('local_recompletion_ssv', [
'userid' => 'privacy:metadata:userid',
'attemptid' => 'privacy:metadata:attempt',
'elementid' => 'privacy:metadata:scoes_value:element',
'value' => 'privacy:metadata:scoes_value:value',
'timemodified' => 'privacy:metadata:timemodified',
'courseid' => 'privacy:metadata:course'
], 'privacy:metadata:scorm_scoes_value');

$collection->add_database_table('local_recompletion_ltia', [
'toolid' => 'privacy:metadata:local_recompletion_ltia:toolid',
Expand Down
36 changes: 28 additions & 8 deletions db/install.xml
Original file line number Diff line number Diff line change
Expand Up @@ -123,27 +123,47 @@
<INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
</INDEXES>
</TABLE>
<TABLE NAME="local_recompletion_sst" COMMENT="archive of scorm_scoes_track table">
<TABLE NAME="local_recompletion_sa" COMMENT="archive of mdl_scorm_attempt table">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="scormid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="attempt" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
<KEY NAME="scormid" TYPE="foreign" FIELDS="scormid" REFTABLE="scorm" REFFIELDS="id"/>
<KEY NAME="courseid" TYPE="foreign" FIELDS="courseid" REFTABLE="course" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
<INDEX NAME="attempt" UNIQUE="false" FIELDS="attempt"/>
<INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
</INDEXES>
</TABLE>
<TABLE NAME="local_recompletion_ssv" COMMENT="archive of mdl_scorm_scoes_value table">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="scoid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="attempt" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="element" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="attemptid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
<FIELD NAME="elementid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="value" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="1" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="scormid" TYPE="foreign" FIELDS="scormid" REFTABLE="scorm" REFFIELDS="id"/>
<KEY NAME="scoid" TYPE="foreign" FIELDS="scoid" REFTABLE="scorm_scoes" REFFIELDS="id"/>
<KEY NAME="attemptid" TYPE="foreign" FIELDS="attemptid" REFTABLE="scorm_attempt" REFFIELDS="id"/>
<KEY NAME="elementid" TYPE="foreign" FIELDS="elementid" REFTABLE="scorm_element" REFFIELDS="id"/>
<KEY NAME="courseid" TYPE="foreign" FIELDS="courseid" REFTABLE="course" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
<INDEX NAME="element" UNIQUE="false" FIELDS="element"/>
<INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
<INDEX NAME="attemptid" UNIQUE="false" FIELDS="attemptid"/>
<INDEX NAME="elementid" UNIQUE="false" FIELDS="elementid"/>
<INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
</INDEXES>
</TABLE>
<TABLE NAME="local_recompletion_config" COMMENT="Configuration for recompletion.">
Expand Down
80 changes: 79 additions & 1 deletion db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -987,5 +987,83 @@ function xmldb_local_recompletion_upgrade($oldversion) {
upgrade_plugin_savepoint(true, 2023112600, 'local', 'recompletion');
}

if ($oldversion < 2024011601) {

// Define table local_recompletion_sa to be created.
$table = new xmldb_table('local_recompletion_sa');

// Adding fields to table local_recompletion_ssv.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('userid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('scormid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('attempt', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');

// Adding keys to table local_recompletion_ssv.
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
$table->add_key('userid', XMLDB_KEY_FOREIGN, array('userid'), 'user', array('id'));
$table->add_key('scormid', XMLDB_KEY_FOREIGN, array('scormid'), 'scorm', array('id'));
$table->add_key('courseid', XMLDB_KEY_FOREIGN, array('courseid'), 'course', array('id'));

// Conditionally launch create table for local_recompletion_ssv.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}

// Define table local_recompletion_ssv to be created.
$table = new xmldb_table('local_recompletion_ssv');

// Adding fields to table local_recompletion_ssv.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('scoid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('attemptid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('elementid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('value', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL, null, null);
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('courseid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');

// Adding keys to table local_recompletion_ssv.
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
$table->add_key('scoid', XMLDB_KEY_FOREIGN, array('scoid'), 'scorm_scoes', array('id'));
$table->add_key('attemptid', XMLDB_KEY_FOREIGN, array('attemptid'), 'scorm_attempt', array('id'));
$table->add_key('elementid', XMLDB_KEY_FOREIGN, array('elementid'), 'scorm_element', array('id'));
$table->add_key('courseid', XMLDB_KEY_FOREIGN, array('courseid'), 'course', array('id'));
// Conditionally launch create table for local_recompletion_ssv.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}
// Migrate Data to new format.
$total = $DB->count_records('local_recompletion_sst');
if ($total > 500000) {
// This site has a large number of user track records, lets warn that this next part may take some time.
$notification = new \core\output\notification(
get_string('largetrackupgrade', 'scorm', format_float($total, 0)),
\core\output\notification::NOTIFY_WARNING
);
$notification->set_show_closebutton(false);
echo $OUTPUT->render($notification);
}
// Fill backup attempt table.
$sql = "INSERT INTO {local_recompletion_sa} (userid, scormid, attempt, courseid)
SELECT userid, scormid, attempt, course FROM {local_recompletion_sst} sst GROUP BY userid,scormid,attempt";
$DB->execute($sql);
// Fill backup value table.
$sql = "INSERT INTO {local_recompletion_ssv} (attemptid, scoid, elementid, value, courseid, timemodified)
SELECT a.id as attemptid, t.scoid as scoid, e.id as elementid, t.value as value, s.course as courseid, t.timemodified
FROM {local_recompletion_sst} t
JOIN {scorm_element} e ON e.element = t.element
LEFT JOIN {scorm} s ON s.id = t.scormid
JOIN {local_recompletion_sa} a ON (t.userid = a.userid AND t.scormid = a.scormid AND a.attempt = t.attempt)";
$DB->execute($sql);
// Remove old table.
$table = new xmldb_table('local_recompletion_sst');
if ($dbman->table_exists($table)) {
$dbman->drop_table($table);
}

// Recompletion savepoint reached.
upgrade_plugin_savepoint(true, 2024011601, 'local', 'recompletion');
}

return true;
}
}
8 changes: 4 additions & 4 deletions lang/en/local_recompletion.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,14 @@
$string['privacy:metadata:quiz_grades:quiz'] = 'The quiz that was graded.';
$string['privacy:metadata:quiz_grades:timemodified'] = 'The time that the grade was modified.';
$string['privacy:metadata:quiz_grades:userid'] = 'The user who was graded.';
$string['privacy:metadata:scoes_track:element'] = 'The name of the element to be tracked';
$string['privacy:metadata:scoes_track:value'] = 'The value of the given element';
$string['privacy:metadata:scoes_value:element'] = 'The ID of the element to be tracked';
$string['privacy:metadata:scoes_value:value'] = 'The value of the given element';
$string['privacy:metadata:coursemoduleid'] = 'The activity ID';
$string['privacy:metadata:completionstate'] = 'If the activity has been completed';
$string['privacy:metadata:viewed'] = 'If the activity was viewed';
$string['privacy:metadata:attempt'] = 'The attempt number';
$string['privacy:metadata:scorm_scoes_track'] = 'Archive of the tracked data of the SCOes belonging to the activity';
$string['privacy:metadata:scorm_attempt'] = 'Archive of previous SCORM attempts.';
$string['privacy:metadata:scorm_scoes_value'] = 'Archive of the tracked data of the SCOes belonging to the activity';
$string['privacy:metadata:local_recompletion_qr:questionnaireid'] = 'Questionnaire id';
$string['privacy:metadata:local_recompletion_qr:submitted'] = 'Submitted';
$string['privacy:metadata:local_recompletion_qr:complete'] = 'complete';
Expand All @@ -159,7 +160,6 @@
$string['privacy:metadata:rawscore'] = 'The score obtained';
$string['privacy:metadata:timecreated'] = 'The time when the tracked element was created';
$string['privacy:metadata:timemodified'] = 'The last time element was tracked';
$string['privacy:metadata:userid'] = 'The ID of the user who accessed the H5P activity';
$string['privacy:metadata:local_recompletion_la'] = 'Archive for lesson_attempts';
$string['privacy:metadata:correct'] = 'Correct answer?';
$string['privacy:metadata:useranswer'] = 'Answer';
Expand Down
8 changes: 4 additions & 4 deletions version.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@

defined('MOODLE_INTERNAL') || die;

$plugin->version = 2023112700;
$plugin->release = 2023112700;
$plugin->version = 2024011601;
$plugin->release = 2024011601;
$plugin->maturity = MATURITY_STABLE;
$plugin->requires = 2022112805; // Requires 4.1.
$plugin->requires = 2023100900; // Requires 4.3.
$plugin->component = 'local_recompletion';
$plugin->supported = [401, 402];
$plugin->supported = [403,403];

0 comments on commit 4d30b3e

Please sign in to comment.