MDL-52501 assign: Fix group submissions without submission record

Based on work by Tim Lock <[email protected]>

While upgrading to Moodle 2.8 or above it is possible for it to fail if
the site has multiple graded attempts for a user without an associated
submission record. This caused the upgrade to violate the databases
unique key rules.

This same issue could apply to a backup that was created of an
assignment that had this issue, when it is restored into Moodle 2.8 or
later.

This change adds the attempt number from the grade table into the query
that is inserting the new submission record (thanks to Tim). It also
moves the insert query before the latest flag is set on submission
records to ensure that only one has it, without this it is possible that
multiple submission records would be marked as the latest after an
upgrade or restore.
This commit is contained in:
Neill Magill
2017-07-06 15:23:40 +01:00
parent 5a651b43fb
commit 733c4978fc
2 changed files with 51 additions and 49 deletions
@@ -282,6 +282,34 @@ class restore_assign_activity_structure_step extends restore_activity_structure_
require_once($CFG->dirroot . '/mod/assign/locallib.php');
$assignmentid = $this->get_new_parentid('assign');
// First check for records with a grade, but no submission record.
// This happens when a teacher marks a student before they have submitted anything.
$records = $DB->get_recordset_sql('SELECT g.id, g.userid, g.attemptnumber
FROM {assign_grades} g
LEFT JOIN {assign_submission} s
ON s.assignment = g.assignment
AND s.userid = g.userid
WHERE s.id IS NULL AND g.assignment = ?', array($assignmentid));
$submissions = array();
foreach ($records as $record) {
$submission = new stdClass();
$submission->assignment = $assignmentid;
$submission->userid = $record->userid;
$submission->attemptnumber = $record->attemptnumber;
$submission->status = ASSIGN_SUBMISSION_STATUS_NEW;
$submission->groupid = 0;
$submission->latest = 0;
$submission->timecreated = time();
$submission->timemodified = time();
array_push($submissions, $submission);
}
$records->close();
$DB->insert_records('assign_submission', $submissions);
// This code could be rewritten as a monster SQL - but the point of adding this "latest" field
// to the submissions table in the first place was to get away from those hard to maintain SQL queries.
@@ -319,32 +347,6 @@ class restore_assign_activity_structure_step extends restore_activity_structure_
$DB->update_record('assign_submission', $submission);
}
}
// Now check for records with a grade, but no submission record.
// This happens when a teacher marks a student before they have submitted anything.
$records = $DB->get_recordset_sql('SELECT g.id, g.userid
FROM {assign_grades} g
LEFT JOIN {assign_submission} s
ON s.assignment = g.assignment
AND s.userid = g.userid
WHERE s.id IS NULL AND g.assignment = ?', array($assignmentid));
$submissions = array();
foreach ($records as $record) {
$submission = new stdClass();
$submission->assignment = $assignmentid;
$submission->userid = $record->userid;
$submission->status = ASSIGN_SUBMISSION_STATUS_NEW;
$submission->groupid = 0;
$submission->latest = 1;
$submission->timecreated = time();
$submission->timemodified = time();
array_push($submissions, $submission);
}
$records->close();
$DB->insert_records('assign_submission', $submissions);
}
/**
+23 -23
View File
@@ -79,6 +79,29 @@ function xmldb_assign_upgrade($oldversion) {
$count = $DB->count_records_sql($countsql, array(1));
if ($count == 0) {
// Look for grade records with no submission record.
// This is when a teacher has marked a student before they submitted anything.
$records = $DB->get_records_sql('SELECT g.id, g.assignment, g.userid, g.attemptnumber
FROM {assign_grades} g
LEFT JOIN {assign_submission} s
ON s.assignment = g.assignment
AND s.userid = g.userid
WHERE s.id IS NULL');
$submissions = array();
foreach ($records as $record) {
$submission = new stdClass();
$submission->assignment = $record->assignment;
$submission->userid = $record->userid;
$submission->attemptnumber = $record->attemptnumber;
$submission->status = 'new';
$submission->groupid = 0;
$submission->latest = 0;
$submission->timecreated = time();
$submission->timemodified = time();
array_push($submissions, $submission);
}
$DB->insert_records('assign_submission', $submissions);
// Mark the latest attempt for every submission in mod_assign.
$maxattemptsql = 'SELECT assignment, userid, groupid, max(attemptnumber) AS maxattempt
@@ -105,29 +128,6 @@ function xmldb_assign_upgrade($oldversion) {
$select = 'id IN(' . $maxattemptidssql . ')';
$DB->set_field_select('assign_submission', 'latest', 1, $select);
}
// Look for grade records with no submission record.
// This is when a teacher has marked a student before they submitted anything.
$records = $DB->get_records_sql('SELECT g.id, g.assignment, g.userid
FROM {assign_grades} g
LEFT JOIN {assign_submission} s
ON s.assignment = g.assignment
AND s.userid = g.userid
WHERE s.id IS NULL');
$submissions = array();
foreach ($records as $record) {
$submission = new stdClass();
$submission->assignment = $record->assignment;
$submission->userid = $record->userid;
$submission->status = 'new';
$submission->groupid = 0;
$submission->latest = 1;
$submission->timecreated = time();
$submission->timemodified = time();
array_push($submissions, $submission);
}
$DB->insert_records('assign_submission', $submissions);
}
// Assign savepoint reached.