See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Define all the restore steps that will be used by the restore_assign_activity_task 19 * 20 * @package mod_assign 21 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 require_once($CFG->dirroot . '/mod/assign/locallib.php'); 28 29 /** 30 * Define the complete assignment structure for restore, with file and id annotations 31 * 32 * @package mod_assign 33 * @copyright 2012 NetSpot {@link http://www.netspot.com.au} 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 */ 36 class restore_assign_activity_structure_step extends restore_activity_structure_step { 37 38 /** 39 * Store whether submission details should be included. Details may not be included if the 40 * this is a team submission, but groups/grouping information was not included in the backup. 41 */ 42 protected $includesubmission = true; 43 44 /** 45 * Define the structure of the restore workflow. 46 * 47 * @return restore_path_element $structure 48 */ 49 protected function define_structure() { 50 51 $paths = array(); 52 // To know if we are including userinfo. 53 $userinfo = $this->get_setting_value('userinfo'); 54 55 // Define each element separated. 56 $paths[] = new restore_path_element('assign', '/activity/assign'); 57 if ($userinfo) { 58 $submission = new restore_path_element('assign_submission', 59 '/activity/assign/submissions/submission'); 60 $paths[] = $submission; 61 $this->add_subplugin_structure('assignsubmission', $submission); 62 $grade = new restore_path_element('assign_grade', '/activity/assign/grades/grade'); 63 $paths[] = $grade; 64 $this->add_subplugin_structure('assignfeedback', $grade); 65 $userflag = new restore_path_element('assign_userflag', 66 '/activity/assign/userflags/userflag'); 67 $paths[] = $userflag; 68 } 69 70 $paths[] = new restore_path_element('assign_override', '/activity/assign/overrides/override'); 71 $paths[] = new restore_path_element('assign_plugin_config', 72 '/activity/assign/plugin_configs/plugin_config'); 73 74 return $this->prepare_activity_structure($paths); 75 } 76 77 /** 78 * Process an assign restore. 79 * 80 * @param object $data The data in object form 81 * @return void 82 */ 83 protected function process_assign($data) { 84 global $DB; 85 86 $data = (object)$data; 87 $oldid = $data->id; 88 $data->course = $this->get_courseid(); 89 90 // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset. 91 // See MDL-9367. 92 $data->allowsubmissionsfromdate = $this->apply_date_offset($data->allowsubmissionsfromdate); 93 $data->duedate = $this->apply_date_offset($data->duedate); 94 95 // If this is a team submission, but there is no group info we need to flag that the submission 96 // information should not be included. It should not be restored. 97 $groupinfo = $this->task->get_setting_value('groups'); 98 if ($data->teamsubmission && !$groupinfo) { 99 $this->includesubmission = false; 100 } 101 102 // Reset revealidentities if blindmarking with no user data (MDL-43796). 103 $userinfo = $this->get_setting_value('userinfo'); 104 if (!$userinfo && $data->blindmarking) { 105 $data->revealidentities = 0; 106 } 107 108 if (!empty($data->teamsubmissiongroupingid)) { 109 $data->teamsubmissiongroupingid = $this->get_mappingid('grouping', 110 $data->teamsubmissiongroupingid); 111 } else { 112 $data->teamsubmissiongroupingid = 0; 113 } 114 if (!isset($data->cutoffdate)) { 115 $data->cutoffdate = 0; 116 } 117 if (!isset($data->gradingduedate)) { 118 $data->gradingduedate = 0; 119 } else { 120 $data->gradingduedate = $this->apply_date_offset($data->gradingduedate); 121 } 122 if (!isset($data->markingworkflow)) { 123 $data->markingworkflow = 0; 124 } 125 if (!isset($data->markingallocation)) { 126 $data->markingallocation = 0; 127 } 128 if (!isset($data->preventsubmissionnotingroup)) { 129 $data->preventsubmissionnotingroup = 0; 130 } 131 132 if (!empty($data->preventlatesubmissions)) { 133 $data->cutoffdate = $data->duedate; 134 } else { 135 $data->cutoffdate = $this->apply_date_offset($data->cutoffdate); 136 } 137 138 if ($data->grade < 0) { // Scale found, get mapping. 139 $data->grade = -($this->get_mappingid('scale', abs($data->grade))); 140 } 141 142 $newitemid = $DB->insert_record('assign', $data); 143 144 $this->apply_activity_instance($newitemid); 145 } 146 147 /** 148 * Process a submission restore 149 * @param object $data The data in object form 150 * @return void 151 */ 152 protected function process_assign_submission($data) { 153 global $DB; 154 155 if (!$this->includesubmission) { 156 return; 157 } 158 159 $data = (object)$data; 160 $oldid = $data->id; 161 162 $data->assignment = $this->get_new_parentid('assign'); 163 164 if ($data->userid > 0) { 165 $data->userid = $this->get_mappingid('user', $data->userid); 166 } 167 if (!empty($data->groupid)) { 168 $data->groupid = $this->get_mappingid('group', $data->groupid); 169 if (!$data->groupid) { 170 // If the group does not exist, then the submission cannot be viewed and restoring can 171 // violate the unique index on the submission table. 172 return; 173 } 174 } else { 175 $data->groupid = 0; 176 } 177 178 // We will correct this in set_latest_submission_field() once all submissions are restored. 179 $data->latest = 0; 180 181 $newitemid = $DB->insert_record('assign_submission', $data); 182 183 // Note - the old contextid is required in order to be able to restore files stored in 184 // sub plugin file areas attached to the submissionid. 185 $this->set_mapping('submission', $oldid, $newitemid, false, null, $this->task->get_old_contextid()); 186 } 187 188 /** 189 * Process a user_flags restore 190 * @param object $data The data in object form 191 * @return void 192 */ 193 protected function process_assign_userflag($data) { 194 global $DB; 195 196 $data = (object)$data; 197 $oldid = $data->id; 198 199 $data->assignment = $this->get_new_parentid('assign'); 200 201 $data->userid = $this->get_mappingid('user', $data->userid); 202 if (!empty($data->allocatedmarker)) { 203 $data->allocatedmarker = $this->get_mappingid('user', $data->allocatedmarker); 204 } 205 if (!empty($data->extensionduedate)) { 206 $data->extensionduedate = $this->apply_date_offset($data->extensionduedate); 207 } else { 208 $data->extensionduedate = 0; 209 } 210 // Flags mailed and locked need no translation on restore. 211 212 $newitemid = $DB->insert_record('assign_user_flags', $data); 213 } 214 215 /** 216 * Process a grade restore 217 * @param object $data The data in object form 218 * @return void 219 */ 220 protected function process_assign_grade($data) { 221 global $DB; 222 223 $data = (object)$data; 224 $oldid = $data->id; 225 226 $data->assignment = $this->get_new_parentid('assign'); 227 228 $data->userid = $this->get_mappingid('user', $data->userid); 229 $data->grader = $this->get_mappingid('user', $data->grader); 230 231 // Handle flags restore to a different table (for upgrade from old backups). 232 if (!empty($data->extensionduedate) || 233 !empty($data->mailed) || 234 !empty($data->locked)) { 235 $flags = new stdClass(); 236 $flags->assignment = $this->get_new_parentid('assign'); 237 if (!empty($data->extensionduedate)) { 238 $flags->extensionduedate = $this->apply_date_offset($data->extensionduedate); 239 } 240 if (!empty($data->mailed)) { 241 $flags->mailed = $data->mailed; 242 } 243 if (!empty($data->locked)) { 244 $flags->locked = $data->locked; 245 } 246 $flags->userid = $this->get_mappingid('user', $data->userid); 247 $DB->insert_record('assign_user_flags', $flags); 248 } 249 // Fix null grades that were rescaled. 250 if ($data->grade < 0 && $data->grade != ASSIGN_GRADE_NOT_SET) { 251 $data->grade = ASSIGN_GRADE_NOT_SET; 252 } 253 $newitemid = $DB->insert_record('assign_grades', $data); 254 255 // Note - the old contextid is required in order to be able to restore files stored in 256 // sub plugin file areas attached to the gradeid. 257 $this->set_mapping('grade', $oldid, $newitemid, false, null, $this->task->get_old_contextid()); 258 $this->set_mapping(restore_gradingform_plugin::itemid_mapping('submissions'), $oldid, $newitemid); 259 } 260 261 /** 262 * Process a plugin-config restore 263 * @param object $data The data in object form 264 * @return void 265 */ 266 protected function process_assign_plugin_config($data) { 267 global $DB; 268 269 $data = (object)$data; 270 $oldid = $data->id; 271 272 $data->assignment = $this->get_new_parentid('assign'); 273 274 $newitemid = $DB->insert_record('assign_plugin_config', $data); 275 } 276 277 /** 278 * For all submissions in this assignment, either set the 279 * submission->latest field to 1 for the latest attempts 280 * or create a new submission record for grades with no submission. 281 * 282 * @return void 283 */ 284 protected function set_latest_submission_field() { 285 global $DB, $CFG; 286 287 // Required for constants. 288 require_once($CFG->dirroot . '/mod/assign/locallib.php'); 289 290 $assignmentid = $this->get_new_parentid('assign'); 291 292 // First check for records with a grade, but no submission record. 293 // This happens when a teacher marks a student before they have submitted anything. 294 $records = $DB->get_recordset_sql('SELECT g.id, g.userid, g.attemptnumber 295 FROM {assign_grades} g 296 LEFT JOIN {assign_submission} s 297 ON s.assignment = g.assignment 298 AND s.userid = g.userid 299 WHERE s.id IS NULL AND g.assignment = ?', array($assignmentid)); 300 301 $submissions = array(); 302 foreach ($records as $record) { 303 $submission = new stdClass(); 304 $submission->assignment = $assignmentid; 305 $submission->userid = $record->userid; 306 $submission->attemptnumber = $record->attemptnumber; 307 $submission->status = ASSIGN_SUBMISSION_STATUS_NEW; 308 $submission->groupid = 0; 309 $submission->latest = 0; 310 $submission->timecreated = time(); 311 $submission->timemodified = time(); 312 array_push($submissions, $submission); 313 } 314 315 $records->close(); 316 317 $DB->insert_records('assign_submission', $submissions); 318 319 // This code could be rewritten as a monster SQL - but the point of adding this "latest" field 320 // to the submissions table in the first place was to get away from those hard to maintain SQL queries. 321 322 // First user submissions. 323 $sql = 'SELECT DISTINCT userid FROM {assign_submission} WHERE assignment = ? AND groupid = ?'; 324 $params = array($assignmentid, 0); 325 $users = $DB->get_records_sql($sql, $params); 326 327 foreach ($users as $userid => $unused) { 328 $params = array('assignment'=>$assignmentid, 'groupid'=>0, 'userid'=>$userid); 329 330 // Only return the row with the highest attemptnumber. 331 $submission = null; 332 $submissions = $DB->get_records('assign_submission', $params, 'attemptnumber DESC', '*', 0, 1); 333 if ($submissions) { 334 $submission = reset($submissions); 335 $submission->latest = 1; 336 $DB->update_record('assign_submission', $submission); 337 } 338 } 339 // Then group submissions (if any). 340 $sql = 'SELECT DISTINCT groupid FROM {assign_submission} WHERE assignment = ? AND userid = ?'; 341 $params = array($assignmentid, 0); 342 $groups = $DB->get_records_sql($sql, $params); 343 344 foreach ($groups as $groupid => $unused) { 345 $params = array('assignment'=>$assignmentid, 'userid'=>0, 'groupid'=>$groupid); 346 347 // Only return the row with the highest attemptnumber. 348 $submission = null; 349 $submissions = $DB->get_records('assign_submission', $params, 'attemptnumber DESC', '*', 0, 1); 350 if ($submissions) { 351 $submission = reset($submissions); 352 $submission->latest = 1; 353 $DB->update_record('assign_submission', $submission); 354 } 355 } 356 } 357 358 /** 359 * Restore files from plugin configuration 360 * @param string $subtype the plugin type to handle 361 * @return void 362 */ 363 protected function add_plugin_config_files($subtype) { 364 $dummyassign = new assign(null, null, null); 365 $plugins = $dummyassign->load_plugins($subtype); 366 foreach ($plugins as $plugin) { 367 $component = $plugin->get_subtype() . '_' . $plugin->get_type(); 368 $areas = $plugin->get_config_file_areas(); 369 foreach ($areas as $area) { 370 $this->add_related_files($component, $area, null); 371 } 372 } 373 } 374 375 /** 376 * Process a assign override restore 377 * @param object $data The data in object form 378 * @return void 379 */ 380 protected function process_assign_override($data) { 381 global $DB; 382 383 $data = (object)$data; 384 $oldid = $data->id; 385 386 // Based on userinfo, we'll restore user overides or no. 387 $userinfo = $this->get_setting_value('userinfo'); 388 389 // Skip user overrides if we are not restoring userinfo. 390 if (!$userinfo && !is_null($data->userid)) { 391 return; 392 } 393 394 // Skip group overrides if we are not restoring groupinfo. 395 $groupinfo = $this->get_setting_value('groups'); 396 if (!$groupinfo && !is_null($data->groupid)) { 397 return; 398 } 399 400 $data->assignid = $this->get_new_parentid('assign'); 401 402 if (!is_null($data->userid)) { 403 $data->userid = $this->get_mappingid('user', $data->userid); 404 } 405 if (!is_null($data->groupid)) { 406 $data->groupid = $this->get_mappingid('group', $data->groupid); 407 } 408 409 $data->allowsubmissionsfromdate = $this->apply_date_offset($data->allowsubmissionsfromdate); 410 $data->duedate = $this->apply_date_offset($data->duedate); 411 $data->cutoffdate = $this->apply_date_offset($data->cutoffdate); 412 413 $newitemid = $DB->insert_record('assign_overrides', $data); 414 415 // Add mapping, restore of logs needs it. 416 $this->set_mapping('assign_override', $oldid, $newitemid); 417 } 418 419 /** 420 * Once the database tables have been fully restored, restore the files 421 * @return void 422 */ 423 protected function after_execute() { 424 $this->add_related_files('mod_assign', 'intro', null); 425 $this->add_related_files('mod_assign', 'introattachment', null); 426 427 $this->add_plugin_config_files('assignsubmission'); 428 $this->add_plugin_config_files('assignfeedback'); 429 430 $this->set_latest_submission_field(); 431 } 432 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body