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:
@@ -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
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user