| 1 | efrain | 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 | use mod_quiz\question\display_options;
 | 
        
           |  |  | 18 |   | 
        
           |  |  | 19 | /**
 | 
        
           |  |  | 20 |  * Structure step to restore one quiz activity
 | 
        
           |  |  | 21 |  *
 | 
        
           |  |  | 22 |  * @package    mod_quiz
 | 
        
           |  |  | 23 |  * @subpackage backup-moodle2
 | 
        
           |  |  | 24 |  * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
 | 
        
           |  |  | 25 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 26 |  */
 | 
        
           |  |  | 27 | class restore_quiz_activity_structure_step extends restore_questions_activity_structure_step {
 | 
        
           |  |  | 28 |   | 
        
           |  |  | 29 |     /**
 | 
        
           |  |  | 30 |      * @var bool tracks whether the quiz contains at least one section. Before
 | 
        
           |  |  | 31 |      * Moodle 2.9 quiz sections did not exist, so if the file being restored
 | 
        
           |  |  | 32 |      * did not contain any, we need to create one in {@link after_execute()}.
 | 
        
           |  |  | 33 |      */
 | 
        
           |  |  | 34 |     protected $sectioncreated = false;
 | 
        
           |  |  | 35 |   | 
        
           |  |  | 36 |     /** @var stdClass|null $currentquizattempt Track the current quiz attempt being restored. */
 | 
        
           |  |  | 37 |     protected $currentquizattempt = null;
 | 
        
           |  |  | 38 |   | 
        
           |  |  | 39 |     /**
 | 
        
           |  |  | 40 |      * @var bool when restoring old quizzes (2.8 or before) this records the
 | 
        
           |  |  | 41 |      * shufflequestionsoption quiz option which has moved to the quiz_sections table.
 | 
        
           |  |  | 42 |      */
 | 
        
           |  |  | 43 |     protected $legacyshufflequestionsoption = false;
 | 
        
           |  |  | 44 |   | 
        
           |  |  | 45 |     /** @var stdClass */
 | 
        
           |  |  | 46 |     protected $oldquizlayout;
 | 
        
           |  |  | 47 |   | 
        
           |  |  | 48 |     /**
 | 
        
           |  |  | 49 |      * @var array Track old question ids that need to be removed at the end of the restore.
 | 
        
           |  |  | 50 |      */
 | 
        
           |  |  | 51 |     protected $oldquestionids = [];
 | 
        
           |  |  | 52 |   | 
        
           |  |  | 53 |     protected function define_structure() {
 | 
        
           |  |  | 54 |   | 
        
           |  |  | 55 |         $paths = [];
 | 
        
           |  |  | 56 |         $userinfo = $this->get_setting_value('userinfo');
 | 
        
           |  |  | 57 |   | 
        
           |  |  | 58 |         $quiz = new restore_path_element('quiz', '/activity/quiz');
 | 
        
           |  |  | 59 |         $paths[] = $quiz;
 | 
        
           |  |  | 60 |   | 
        
           |  |  | 61 |         // A chance for access subplugings to set up their quiz data.
 | 
        
           |  |  | 62 |         $this->add_subplugin_structure('quizaccess', $quiz);
 | 
        
           |  |  | 63 |   | 
        
           |  |  | 64 |         $paths[] = new restore_path_element('quiz_grade_item', '/activity/quiz/quiz_grade_items/quiz_grade_item');
 | 
        
           |  |  | 65 |         $quizquestioninstance = new restore_path_element('quiz_question_instance',
 | 
        
           |  |  | 66 |             '/activity/quiz/question_instances/question_instance');
 | 
        
           |  |  | 67 |         $paths[] = $quizquestioninstance;
 | 
        
           |  |  | 68 |         if ($this->task->get_old_moduleversion() < 2021091700) {
 | 
        
           |  |  | 69 |             $paths[] = new restore_path_element('quiz_slot_tags',
 | 
        
           |  |  | 70 |                 '/activity/quiz/question_instances/question_instance/tags/tag');
 | 
        
           |  |  | 71 |         } else {
 | 
        
           |  |  | 72 |             $this->add_question_references($quizquestioninstance, $paths);
 | 
        
           |  |  | 73 |             $this->add_question_set_references($quizquestioninstance, $paths);
 | 
        
           |  |  | 74 |         }
 | 
        
           |  |  | 75 |         $paths[] = new restore_path_element('quiz_section', '/activity/quiz/sections/section');
 | 
        
           |  |  | 76 |         $paths[] = new restore_path_element('quiz_feedback', '/activity/quiz/feedbacks/feedback');
 | 
        
           |  |  | 77 |         $paths[] = new restore_path_element('quiz_override', '/activity/quiz/overrides/override');
 | 
        
           |  |  | 78 |   | 
        
           |  |  | 79 |         if ($userinfo) {
 | 
        
           |  |  | 80 |             $paths[] = new restore_path_element('quiz_grade', '/activity/quiz/grades/grade');
 | 
        
           |  |  | 81 |   | 
        
           |  |  | 82 |             if ($this->task->get_old_moduleversion() > 2011010100) {
 | 
        
           |  |  | 83 |                 // Restoring from a version 2.1 dev or later.
 | 
        
           |  |  | 84 |                 // Process the new-style attempt data.
 | 
        
           |  |  | 85 |                 $quizattempt = new restore_path_element('quiz_attempt',
 | 
        
           |  |  | 86 |                         '/activity/quiz/attempts/attempt');
 | 
        
           |  |  | 87 |                 $paths[] = $quizattempt;
 | 
        
           |  |  | 88 |   | 
        
           |  |  | 89 |                 // Add states and sessions.
 | 
        
           |  |  | 90 |                 $this->add_question_usages($quizattempt, $paths);
 | 
        
           |  |  | 91 |   | 
        
           |  |  | 92 |                 // A chance for access subplugings to set up their attempt data.
 | 
        
           |  |  | 93 |                 $this->add_subplugin_structure('quizaccess', $quizattempt);
 | 
        
           |  |  | 94 |   | 
        
           |  |  | 95 |             } else {
 | 
        
           |  |  | 96 |                 // Restoring from a version 2.0.x+ or earlier.
 | 
        
           |  |  | 97 |                 // Upgrade the legacy attempt data.
 | 
        
           |  |  | 98 |                 $quizattempt = new restore_path_element('quiz_attempt_legacy',
 | 
        
           |  |  | 99 |                         '/activity/quiz/attempts/attempt',
 | 
        
           |  |  | 100 |                         true);
 | 
        
           |  |  | 101 |                 $paths[] = $quizattempt;
 | 
        
           |  |  | 102 |                 $this->add_legacy_question_attempt_data($quizattempt, $paths);
 | 
        
           |  |  | 103 |             }
 | 
        
           |  |  | 104 |         }
 | 
        
           |  |  | 105 |   | 
        
           |  |  | 106 |         // Return the paths wrapped into standard activity structure.
 | 
        
           |  |  | 107 |         return $this->prepare_activity_structure($paths);
 | 
        
           |  |  | 108 |     }
 | 
        
           |  |  | 109 |   | 
        
           |  |  | 110 |     /**
 | 
        
           |  |  | 111 |      * Process the quiz data.
 | 
        
           |  |  | 112 |      *
 | 
        
           |  |  | 113 |      * @param stdClass|array $data
 | 
        
           |  |  | 114 |      */
 | 
        
           |  |  | 115 |     protected function process_quiz($data) {
 | 
        
           |  |  | 116 |         global $CFG, $DB, $USER;
 | 
        
           |  |  | 117 |   | 
        
           |  |  | 118 |         $data = (object)$data;
 | 
        
           |  |  | 119 |         $oldid = $data->id;
 | 
        
           |  |  | 120 |         $data->course = $this->get_courseid();
 | 
        
           |  |  | 121 |   | 
        
           |  |  | 122 |         // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
 | 
        
           |  |  | 123 |         // See MDL-9367.
 | 
        
           |  |  | 124 |   | 
        
           |  |  | 125 |         $data->timeopen = $this->apply_date_offset($data->timeopen);
 | 
        
           |  |  | 126 |         $data->timeclose = $this->apply_date_offset($data->timeclose);
 | 
        
           |  |  | 127 |   | 
        
           |  |  | 128 |         if (property_exists($data, 'questions')) {
 | 
        
           |  |  | 129 |             // Needed by {@link process_quiz_attempt_legacy}, in which case it will be present.
 | 
        
           |  |  | 130 |             $this->oldquizlayout = $data->questions;
 | 
        
           |  |  | 131 |         }
 | 
        
           |  |  | 132 |   | 
        
           |  |  | 133 |         // The setting quiz->attempts can come both in data->attempts and
 | 
        
           |  |  | 134 |         // data->attempts_number, handle both. MDL-26229.
 | 
        
           |  |  | 135 |         if (isset($data->attempts_number)) {
 | 
        
           |  |  | 136 |             $data->attempts = $data->attempts_number;
 | 
        
           |  |  | 137 |             unset($data->attempts_number);
 | 
        
           |  |  | 138 |         }
 | 
        
           |  |  | 139 |   | 
        
           |  |  | 140 |         // The old optionflags and penaltyscheme from 2.0 need to be mapped to
 | 
        
           |  |  | 141 |         // the new preferredbehaviour. See MDL-20636.
 | 
        
           |  |  | 142 |         if (!isset($data->preferredbehaviour)) {
 | 
        
           |  |  | 143 |             if (empty($data->optionflags)) {
 | 
        
           |  |  | 144 |                 $data->preferredbehaviour = 'deferredfeedback';
 | 
        
           |  |  | 145 |             } else if (empty($data->penaltyscheme)) {
 | 
        
           |  |  | 146 |                 $data->preferredbehaviour = 'adaptivenopenalty';
 | 
        
           |  |  | 147 |             } else {
 | 
        
           |  |  | 148 |                 $data->preferredbehaviour = 'adaptive';
 | 
        
           |  |  | 149 |             }
 | 
        
           |  |  | 150 |             unset($data->optionflags);
 | 
        
           |  |  | 151 |             unset($data->penaltyscheme);
 | 
        
           |  |  | 152 |         }
 | 
        
           |  |  | 153 |   | 
        
           |  |  | 154 |         // The old review column from 2.0 need to be split into the seven new
 | 
        
           |  |  | 155 |         // review columns. See MDL-20636.
 | 
        
           |  |  | 156 |         if (isset($data->review)) {
 | 
        
           |  |  | 157 |             require_once($CFG->dirroot . '/mod/quiz/locallib.php');
 | 
        
           |  |  | 158 |   | 
        
           |  |  | 159 |             if (!defined('QUIZ_OLD_IMMEDIATELY')) {
 | 
        
           |  |  | 160 |                 define('QUIZ_OLD_IMMEDIATELY', 0x3c003f);
 | 
        
           |  |  | 161 |                 define('QUIZ_OLD_OPEN',        0x3c00fc0);
 | 
        
           |  |  | 162 |                 define('QUIZ_OLD_CLOSED',      0x3c03f000);
 | 
        
           |  |  | 163 |   | 
        
           |  |  | 164 |                 define('QUIZ_OLD_RESPONSES',        1*0x1041);
 | 
        
           |  |  | 165 |                 define('QUIZ_OLD_SCORES',           2*0x1041);
 | 
        
           |  |  | 166 |                 define('QUIZ_OLD_FEEDBACK',         4*0x1041);
 | 
        
           |  |  | 167 |                 define('QUIZ_OLD_ANSWERS',          8*0x1041);
 | 
        
           |  |  | 168 |                 define('QUIZ_OLD_SOLUTIONS',       16*0x1041);
 | 
        
           |  |  | 169 |                 define('QUIZ_OLD_GENERALFEEDBACK', 32*0x1041);
 | 
        
           |  |  | 170 |                 define('QUIZ_OLD_OVERALLFEEDBACK',  1*0x4440000);
 | 
        
           |  |  | 171 |             }
 | 
        
           |  |  | 172 |   | 
        
           |  |  | 173 |             $oldreview = $data->review;
 | 
        
           |  |  | 174 |   | 
        
           |  |  | 175 |             $data->reviewattempt =
 | 
        
           |  |  | 176 |                     display_options::DURING |
 | 
        
           |  |  | 177 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_RESPONSES ?
 | 
        
           |  |  | 178 |                             display_options::IMMEDIATELY_AFTER : 0) |
 | 
        
           |  |  | 179 |                     ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_RESPONSES ?
 | 
        
           |  |  | 180 |                             display_options::LATER_WHILE_OPEN : 0) |
 | 
        
           |  |  | 181 |                     ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_RESPONSES ?
 | 
        
           |  |  | 182 |                             display_options::AFTER_CLOSE : 0);
 | 
        
           |  |  | 183 |   | 
        
           |  |  | 184 |             $data->reviewcorrectness =
 | 
        
           |  |  | 185 |                     display_options::DURING |
 | 
        
           |  |  | 186 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_SCORES ?
 | 
        
           |  |  | 187 |                             display_options::IMMEDIATELY_AFTER : 0) |
 | 
        
           |  |  | 188 |                     ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_SCORES ?
 | 
        
           |  |  | 189 |                             display_options::LATER_WHILE_OPEN : 0) |
 | 
        
           |  |  | 190 |                     ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_SCORES ?
 | 
        
           |  |  | 191 |                             display_options::AFTER_CLOSE : 0);
 | 
        
           |  |  | 192 |   | 
        
           |  |  | 193 |             $data->reviewmarks =
 | 
        
           |  |  | 194 |                     display_options::DURING |
 | 
        
           |  |  | 195 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_SCORES ?
 | 
        
           |  |  | 196 |                             display_options::IMMEDIATELY_AFTER : 0) |
 | 
        
           |  |  | 197 |                     ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_SCORES ?
 | 
        
           |  |  | 198 |                             display_options::LATER_WHILE_OPEN : 0) |
 | 
        
           |  |  | 199 |                     ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_SCORES ?
 | 
        
           |  |  | 200 |                             display_options::AFTER_CLOSE : 0);
 | 
        
           |  |  | 201 |   | 
        
           |  |  | 202 |             $data->reviewspecificfeedback =
 | 
        
           |  |  | 203 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_FEEDBACK ?
 | 
        
           |  |  | 204 |                             display_options::DURING : 0) |
 | 
        
           |  |  | 205 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_FEEDBACK ?
 | 
        
           |  |  | 206 |                             display_options::IMMEDIATELY_AFTER : 0) |
 | 
        
           |  |  | 207 |                     ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_FEEDBACK ?
 | 
        
           |  |  | 208 |                             display_options::LATER_WHILE_OPEN : 0) |
 | 
        
           |  |  | 209 |                     ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_FEEDBACK ?
 | 
        
           |  |  | 210 |                             display_options::AFTER_CLOSE : 0);
 | 
        
           |  |  | 211 |   | 
        
           |  |  | 212 |             $data->reviewgeneralfeedback =
 | 
        
           |  |  | 213 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_GENERALFEEDBACK ?
 | 
        
           |  |  | 214 |                             display_options::DURING : 0) |
 | 
        
           |  |  | 215 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_GENERALFEEDBACK ?
 | 
        
           |  |  | 216 |                             display_options::IMMEDIATELY_AFTER : 0) |
 | 
        
           |  |  | 217 |                     ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_GENERALFEEDBACK ?
 | 
        
           |  |  | 218 |                             display_options::LATER_WHILE_OPEN : 0) |
 | 
        
           |  |  | 219 |                     ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_GENERALFEEDBACK ?
 | 
        
           |  |  | 220 |                             display_options::AFTER_CLOSE : 0);
 | 
        
           |  |  | 221 |   | 
        
           |  |  | 222 |             $data->reviewrightanswer =
 | 
        
           |  |  | 223 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_ANSWERS ?
 | 
        
           |  |  | 224 |                             display_options::DURING : 0) |
 | 
        
           |  |  | 225 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_ANSWERS ?
 | 
        
           |  |  | 226 |                             display_options::IMMEDIATELY_AFTER : 0) |
 | 
        
           |  |  | 227 |                     ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_ANSWERS ?
 | 
        
           |  |  | 228 |                             display_options::LATER_WHILE_OPEN : 0) |
 | 
        
           |  |  | 229 |                     ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_ANSWERS ?
 | 
        
           |  |  | 230 |                             display_options::AFTER_CLOSE : 0);
 | 
        
           |  |  | 231 |   | 
        
           |  |  | 232 |             $data->reviewoverallfeedback =
 | 
        
           |  |  | 233 |   | 
        
           |  |  | 234 |                     ($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_OVERALLFEEDBACK ?
 | 
        
           |  |  | 235 |                             display_options::IMMEDIATELY_AFTER : 0) |
 | 
        
           |  |  | 236 |                     ($oldreview & QUIZ_OLD_OPEN & QUIZ_OLD_OVERALLFEEDBACK ?
 | 
        
           |  |  | 237 |                             display_options::LATER_WHILE_OPEN : 0) |
 | 
        
           |  |  | 238 |                     ($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_OVERALLFEEDBACK ?
 | 
        
           |  |  | 239 |                             display_options::AFTER_CLOSE : 0);
 | 
        
           |  |  | 240 |         }
 | 
        
           |  |  | 241 |   | 
        
           |  |  | 242 |         // New setting in 4.3 needs to be set if not in the backup.
 | 
        
           |  |  | 243 |         if (!isset($data->reviewmaxmarks)) {
 | 
        
           |  |  | 244 |             $data->reviewmaxmarks =
 | 
        
           |  |  | 245 |                     display_options::DURING |
 | 
        
           |  |  | 246 |                     display_options::IMMEDIATELY_AFTER |
 | 
        
           |  |  | 247 |                     display_options::LATER_WHILE_OPEN |
 | 
        
           |  |  | 248 |                     display_options::AFTER_CLOSE;
 | 
        
           |  |  | 249 |         }
 | 
        
           |  |  | 250 |   | 
        
           |  |  | 251 |         // The old popup column from from <= 2.1 need to be mapped to
 | 
        
           |  |  | 252 |         // the new browsersecurity. See MDL-29627.
 | 
        
           |  |  | 253 |         if (!isset($data->browsersecurity)) {
 | 
        
           |  |  | 254 |             if (empty($data->popup)) {
 | 
        
           |  |  | 255 |                 $data->browsersecurity = '-';
 | 
        
           |  |  | 256 |             } else if ($data->popup == 1) {
 | 
        
           |  |  | 257 |                 $data->browsersecurity = 'securewindow';
 | 
        
           |  |  | 258 |             } else if ($data->popup == 2) {
 | 
        
           |  |  | 259 |                 // Since 3.9 quizaccess_safebrowser replaced with a new quizaccess_seb.
 | 
        
           |  |  | 260 |                 $data->browsersecurity = '-';
 | 
        
           |  |  | 261 |                 $addsebrule = true;
 | 
        
           |  |  | 262 |             } else {
 | 
        
           |  |  | 263 |                 $data->preferredbehaviour = '-';
 | 
        
           |  |  | 264 |             }
 | 
        
           |  |  | 265 |             unset($data->popup);
 | 
        
           |  |  | 266 |         } else if ($data->browsersecurity == 'safebrowser') {
 | 
        
           |  |  | 267 |             // Since 3.9 quizaccess_safebrowser replaced with a new quizaccess_seb.
 | 
        
           |  |  | 268 |             $data->browsersecurity = '-';
 | 
        
           |  |  | 269 |             $addsebrule = true;
 | 
        
           |  |  | 270 |         }
 | 
        
           |  |  | 271 |   | 
        
           |  |  | 272 |         if (!isset($data->overduehandling)) {
 | 
        
           |  |  | 273 |             $data->overduehandling = get_config('quiz', 'overduehandling');
 | 
        
           |  |  | 274 |         }
 | 
        
           |  |  | 275 |   | 
        
           |  |  | 276 |         // Old shufflequestions setting is now stored in quiz sections,
 | 
        
           |  |  | 277 |         // so save it here if necessary so it is available when we need it.
 | 
        
           |  |  | 278 |         $this->legacyshufflequestionsoption = !empty($data->shufflequestions);
 | 
        
           |  |  | 279 |   | 
        
           |  |  | 280 |         // Insert the quiz record.
 | 
        
           |  |  | 281 |         $newitemid = $DB->insert_record('quiz', $data);
 | 
        
           |  |  | 282 |         // Immediately after inserting "activity" record, call this.
 | 
        
           |  |  | 283 |         $this->apply_activity_instance($newitemid);
 | 
        
           |  |  | 284 |   | 
        
           |  |  | 285 |         // Process Safe Exam Browser settings for backups taken in Moodle < 3.9.
 | 
        
           |  |  | 286 |         if (!empty($addsebrule)) {
 | 
        
           |  |  | 287 |             $sebsettings = new stdClass();
 | 
        
           |  |  | 288 |   | 
        
           |  |  | 289 |             $sebsettings->quizid = $newitemid;
 | 
        
           |  |  | 290 |             $sebsettings->cmid = $this->task->get_moduleid();
 | 
        
           |  |  | 291 |             $sebsettings->templateid = 0;
 | 
        
           |  |  | 292 |             $sebsettings->requiresafeexambrowser = \quizaccess_seb\settings_provider::USE_SEB_CLIENT_CONFIG;
 | 
        
           |  |  | 293 |             $sebsettings->showsebtaskbar = null;
 | 
        
           |  |  | 294 |             $sebsettings->showwificontrol = null;
 | 
        
           |  |  | 295 |             $sebsettings->showreloadbutton = null;
 | 
        
           |  |  | 296 |             $sebsettings->showtime = null;
 | 
        
           |  |  | 297 |             $sebsettings->showkeyboardlayout = null;
 | 
        
           |  |  | 298 |             $sebsettings->allowuserquitseb = null;
 | 
        
           |  |  | 299 |             $sebsettings->quitpassword = null;
 | 
        
           |  |  | 300 |             $sebsettings->linkquitseb = null;
 | 
        
           |  |  | 301 |             $sebsettings->userconfirmquit = null;
 | 
        
           |  |  | 302 |             $sebsettings->enableaudiocontrol = null;
 | 
        
           |  |  | 303 |             $sebsettings->muteonstartup = null;
 | 
        
           |  |  | 304 |             $sebsettings->allowspellchecking = null;
 | 
        
           |  |  | 305 |             $sebsettings->allowreloadinexam = null;
 | 
        
           |  |  | 306 |             $sebsettings->activateurlfiltering = null;
 | 
        
           |  |  | 307 |             $sebsettings->filterembeddedcontent = null;
 | 
        
           |  |  | 308 |             $sebsettings->expressionsallowed = null;
 | 
        
           |  |  | 309 |             $sebsettings->regexallowed = null;
 | 
        
           |  |  | 310 |             $sebsettings->expressionsblocked = null;
 | 
        
           |  |  | 311 |             $sebsettings->regexblocked = null;
 | 
        
           |  |  | 312 |             $sebsettings->allowedbrowserexamkeys = null;
 | 
        
           |  |  | 313 |             $sebsettings->showsebdownloadlink = 1;
 | 
        
           |  |  | 314 |             $sebsettings->usermodified = $USER->id;
 | 
        
           |  |  | 315 |             $sebsettings->timecreated = time();
 | 
        
           |  |  | 316 |             $sebsettings->timemodified = time();
 | 
        
           |  |  | 317 |   | 
        
           |  |  | 318 |             $DB->insert_record('quizaccess_seb_quizsettings', $sebsettings);
 | 
        
           |  |  | 319 |         }
 | 
        
           |  |  | 320 |   | 
        
           |  |  | 321 |         // If we are dealing with a backup from < 4.0 then we need to move completionpass to core.
 | 
        
           |  |  | 322 |         if (!empty($data->completionpass)) {
 | 
        
           |  |  | 323 |             $params = ['id' => $this->task->get_moduleid()];
 | 
        
           |  |  | 324 |             $DB->set_field('course_modules', 'completionpassgrade', $data->completionpass, $params);
 | 
        
           |  |  | 325 |         }
 | 
        
           |  |  | 326 |     }
 | 
        
           |  |  | 327 |   | 
        
           |  |  | 328 |     /**
 | 
        
           |  |  | 329 |      * Process a quiz grade items.
 | 
        
           |  |  | 330 |      *
 | 
        
           |  |  | 331 |      * @param stdClass|array $data
 | 
        
           |  |  | 332 |      */
 | 
        
           |  |  | 333 |     protected function process_quiz_grade_item($data): void {
 | 
        
           |  |  | 334 |         global $DB;
 | 
        
           |  |  | 335 |   | 
        
           |  |  | 336 |         $data = (object) $data;
 | 
        
           |  |  | 337 |         $data->quizid = $this->get_new_parentid('quiz');
 | 
        
           |  |  | 338 |         $oldid = $data->id;
 | 
        
           |  |  | 339 |         $newitemid = $DB->insert_record('quiz_grade_items', $data);
 | 
        
           |  |  | 340 |         $this->set_mapping('quiz_grade_item', $oldid, $newitemid, true);
 | 
        
           |  |  | 341 |     }
 | 
        
           |  |  | 342 |   | 
        
           |  |  | 343 |     /**
 | 
        
           |  |  | 344 |      * Process the data for pre 4.0 quiz data where the question_references and question_set_references table introduced.
 | 
        
           |  |  | 345 |      *
 | 
        
           |  |  | 346 |      * @param stdClass|array $data
 | 
        
           |  |  | 347 |      */
 | 
        
           |  |  | 348 |     protected function process_quiz_question_legacy_instance($data) {
 | 
        
           |  |  | 349 |         global $DB;
 | 
        
           |  |  | 350 |   | 
        
           |  |  | 351 |         $questionid = $this->get_mappingid('question', $data->questionid);
 | 
        
           |  |  | 352 |         $sql = 'SELECT qbe.id as questionbankentryid,
 | 
        
           |  |  | 353 |                        qc.contextid as questioncontextid,
 | 
        
           |  |  | 354 |                        qc.id as category,
 | 
        
           |  |  | 355 |                        qv.version,
 | 
        
           |  |  | 356 |                        q.qtype,
 | 
        
           |  |  | 357 |                        q.id as questionid
 | 
        
           |  |  | 358 |                   FROM {question} q
 | 
        
           |  |  | 359 |                   JOIN {question_versions} qv ON qv.questionid = q.id
 | 
        
           |  |  | 360 |                   JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
 | 
        
           |  |  | 361 |                   JOIN {question_categories} qc ON qc.id = qbe.questioncategoryid
 | 
        
           |  |  | 362 |                  WHERE q.id = ?';
 | 
        
           |  |  | 363 |         $question = $DB->get_record_sql($sql, [$questionid]);
 | 
        
           |  |  | 364 |         $module = $DB->get_record('quiz', ['id' => $data->quizid]);
 | 
        
           |  |  | 365 |   | 
        
           |  |  | 366 |         if ($question->qtype === 'random') {
 | 
        
           |  |  | 367 |             // Set reference data.
 | 
        
           |  |  | 368 |             $questionsetreference = new stdClass();
 | 
        
           |  |  | 369 |             $questionsetreference->usingcontextid = context_module::instance(get_coursemodule_from_instance(
 | 
        
           |  |  | 370 |                 "quiz", $module->id, $module->course)->id)->id;
 | 
        
           |  |  | 371 |             $questionsetreference->component = 'mod_quiz';
 | 
        
           |  |  | 372 |             $questionsetreference->questionarea = 'slot';
 | 
        
           |  |  | 373 |             $questionsetreference->itemid = $data->id;
 | 
        
           |  |  | 374 |             // If, in the orginal quiz that was backed up, this random question was pointing to a
 | 
        
           |  |  | 375 |             // category in the quiz question bank, then (for reasons explained in {@see restore_move_module_questions_categories})
 | 
        
           |  |  | 376 |             // right now, $question->questioncontextid will incorrectly point to the course contextid.
 | 
        
           |  |  | 377 |             // This will get fixed up later in restore_move_module_questions_categories
 | 
        
           |  |  | 378 |             // as part of moving the question categories to the right place.
 | 
        
           |  |  | 379 |             $questionsetreference->questionscontextid = $question->questioncontextid;
 | 
        
           |  |  | 380 |             $filtercondition = new stdClass();
 | 
        
           |  |  | 381 |             $filtercondition->questioncategoryid = $question->category;
 | 
        
           |  |  | 382 |             $filtercondition->includingsubcategories = $data->includingsubcategories ?? false;
 | 
        
           |  |  | 383 |             $questionsetreference->filtercondition = json_encode($filtercondition);
 | 
        
           |  |  | 384 |             $DB->insert_record('question_set_references', $questionsetreference);
 | 
        
           |  |  | 385 |             $this->oldquestionids[$question->questionid] = 1;
 | 
        
           |  |  | 386 |         } else {
 | 
        
           |  |  | 387 |             // Reference data.
 | 
        
           |  |  | 388 |             $questionreference = new \stdClass();
 | 
        
           |  |  | 389 |             $questionreference->usingcontextid = context_module::instance(get_coursemodule_from_instance(
 | 
        
           |  |  | 390 |                 "quiz", $module->id, $module->course)->id)->id;
 | 
        
           |  |  | 391 |             $questionreference->component = 'mod_quiz';
 | 
        
           |  |  | 392 |             $questionreference->questionarea = 'slot';
 | 
        
           |  |  | 393 |             $questionreference->itemid = $data->id;
 | 
        
           |  |  | 394 |             $questionreference->questionbankentryid = $question->questionbankentryid;
 | 
        
           |  |  | 395 |             $questionreference->version = null; // Default to Always latest.
 | 
        
           |  |  | 396 |             $DB->insert_record('question_references', $questionreference);
 | 
        
           |  |  | 397 |         }
 | 
        
           |  |  | 398 |     }
 | 
        
           |  |  | 399 |   | 
        
           |  |  | 400 |     /**
 | 
        
           |  |  | 401 |      * Process quiz slots.
 | 
        
           |  |  | 402 |      *
 | 
        
           |  |  | 403 |      * @param stdClass|array $data
 | 
        
           |  |  | 404 |      */
 | 
        
           |  |  | 405 |     protected function process_quiz_question_instance($data) {
 | 
        
           |  |  | 406 |         global $DB;
 | 
        
           |  |  | 407 |   | 
        
           |  |  | 408 |         $data = (object)$data;
 | 
        
           |  |  | 409 |         $oldid = $data->id;
 | 
        
           |  |  | 410 |   | 
        
           |  |  | 411 |         // Backwards compatibility for old field names (MDL-43670).
 | 
        
           |  |  | 412 |         if (!isset($data->questionid) && isset($data->question)) {
 | 
        
           |  |  | 413 |             $data->questionid = $data->question;
 | 
        
           |  |  | 414 |         }
 | 
        
           |  |  | 415 |         if (!isset($data->maxmark) && isset($data->grade)) {
 | 
        
           |  |  | 416 |             $data->maxmark = $data->grade;
 | 
        
           |  |  | 417 |         }
 | 
        
           |  |  | 418 |   | 
        
           |  |  | 419 |         if (!property_exists($data, 'slot')) {
 | 
        
           |  |  | 420 |             $page = 1;
 | 
        
           |  |  | 421 |             $slot = 1;
 | 
        
           |  |  | 422 |             foreach (explode(',', $this->oldquizlayout) as $item) {
 | 
        
           |  |  | 423 |                 if ($item == 0) {
 | 
        
           |  |  | 424 |                     $page += 1;
 | 
        
           |  |  | 425 |                     continue;
 | 
        
           |  |  | 426 |                 }
 | 
        
           |  |  | 427 |                 if (isset($data->questionid) && $item == $data->questionid) {
 | 
        
           |  |  | 428 |                     $data->slot = $slot;
 | 
        
           |  |  | 429 |                     $data->page = $page;
 | 
        
           |  |  | 430 |                     break;
 | 
        
           |  |  | 431 |                 }
 | 
        
           |  |  | 432 |                 $slot += 1;
 | 
        
           |  |  | 433 |             }
 | 
        
           |  |  | 434 |         }
 | 
        
           |  |  | 435 |   | 
        
           |  |  | 436 |         if (!property_exists($data, 'slot')) {
 | 
        
           |  |  | 437 |             // There was a question_instance in the backup file for a question
 | 
        
           |  |  | 438 |             // that was not actually in the quiz. Drop it.
 | 
        
           |  |  | 439 |             $this->log('question ' . $data->questionid . ' was associated with quiz ' .
 | 
        
           |  |  | 440 |                     $this->get_new_parentid('quiz') . ' but not actually used. ' .
 | 
        
           |  |  | 441 |                     'The instance has been ignored.', backup::LOG_INFO);
 | 
        
           |  |  | 442 |             return;
 | 
        
           |  |  | 443 |         }
 | 
        
           |  |  | 444 |   | 
        
           |  |  | 445 |         if (isset($data->quizgradeitemid)) {
 | 
        
           |  |  | 446 |             $data->quizgradeitemid = $this->get_mappingid('quiz_grade_item', $data->quizgradeitemid);
 | 
        
           |  |  | 447 |         }
 | 
        
           |  |  | 448 |   | 
        
           |  |  | 449 |         $data->quizid = $this->get_new_parentid('quiz');
 | 
        
           |  |  | 450 |   | 
        
           |  |  | 451 |         $newitemid = $DB->insert_record('quiz_slots', $data);
 | 
        
           |  |  | 452 |         // Add mapping, restore of slot tags (for random questions) need it.
 | 
        
           |  |  | 453 |         $this->set_mapping('quiz_question_instance', $oldid, $newitemid);
 | 
        
           |  |  | 454 |   | 
        
           |  |  | 455 |         if ($this->task->get_old_moduleversion() < 2022020300) {
 | 
        
           |  |  | 456 |             $data->id = $newitemid;
 | 
        
           |  |  | 457 |             $this->process_quiz_question_legacy_instance($data);
 | 
        
           |  |  | 458 |         }
 | 
        
           |  |  | 459 |     }
 | 
        
           |  |  | 460 |   | 
        
           |  |  | 461 |     /**
 | 
        
           |  |  | 462 |      * Process a quiz_slot_tags to restore the tags to the new structure.
 | 
        
           |  |  | 463 |      *
 | 
        
           |  |  | 464 |      * @param stdClass|array $data The quiz_slot_tags data
 | 
        
           |  |  | 465 |      */
 | 
        
           |  |  | 466 |     protected function process_quiz_slot_tags($data) {
 | 
        
           |  |  | 467 |         global $DB;
 | 
        
           |  |  | 468 |   | 
        
           |  |  | 469 |         $data = (object) $data;
 | 
        
           |  |  | 470 |         $slotid = $this->get_new_parentid('quiz_question_instance');
 | 
        
           |  |  | 471 |   | 
        
           |  |  | 472 |         if ($this->task->is_samesite() && $tag = core_tag_tag::get($data->tagid, 'id, name')) {
 | 
        
           |  |  | 473 |             $data->tagname = $tag->name;
 | 
        
           |  |  | 474 |         } else if ($tag = core_tag_tag::get_by_name(0, $data->tagname, 'id, name')) {
 | 
        
           |  |  | 475 |             $data->tagid = $tag->id;
 | 
        
           |  |  | 476 |         } else {
 | 
        
           |  |  | 477 |             $data->tagid = null;
 | 
        
           |  |  | 478 |             $data->tagname = $tag->name;
 | 
        
           |  |  | 479 |         }
 | 
        
           |  |  | 480 |   | 
        
           |  |  | 481 |         $tagstring = "{$data->tagid},{$data->tagname}";
 | 
        
           |  |  | 482 |         $setreferencedata = $DB->get_record('question_set_references',
 | 
        
           |  |  | 483 |             ['itemid' => $slotid, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
 | 
        
           |  |  | 484 |         $filtercondition = json_decode($setreferencedata->filtercondition);
 | 
        
           |  |  | 485 |         $filtercondition->tags[] = $tagstring;
 | 
        
           |  |  | 486 |         $setreferencedata->filtercondition = json_encode($filtercondition);
 | 
        
           |  |  | 487 |         $DB->update_record('question_set_references', $setreferencedata);
 | 
        
           |  |  | 488 |     }
 | 
        
           |  |  | 489 |   | 
        
           |  |  | 490 |     protected function process_quiz_section($data) {
 | 
        
           |  |  | 491 |         global $DB;
 | 
        
           |  |  | 492 |   | 
        
           |  |  | 493 |         $data = (object) $data;
 | 
        
           |  |  | 494 |         $data->quizid = $this->get_new_parentid('quiz');
 | 
        
           |  |  | 495 |         $oldid = $data->id;
 | 
        
           |  |  | 496 |         $newitemid = $DB->insert_record('quiz_sections', $data);
 | 
        
           |  |  | 497 |         $this->sectioncreated = true;
 | 
        
           |  |  | 498 |         $this->set_mapping('quiz_section', $oldid, $newitemid, true);
 | 
        
           |  |  | 499 |     }
 | 
        
           |  |  | 500 |   | 
        
           |  |  | 501 |     protected function process_quiz_feedback($data) {
 | 
        
           |  |  | 502 |         global $DB;
 | 
        
           |  |  | 503 |   | 
        
           |  |  | 504 |         $data = (object)$data;
 | 
        
           |  |  | 505 |         $oldid = $data->id;
 | 
        
           |  |  | 506 |   | 
        
           |  |  | 507 |         $data->quizid = $this->get_new_parentid('quiz');
 | 
        
           |  |  | 508 |   | 
        
           |  |  | 509 |         $newitemid = $DB->insert_record('quiz_feedback', $data);
 | 
        
           |  |  | 510 |         $this->set_mapping('quiz_feedback', $oldid, $newitemid, true); // Has related files.
 | 
        
           |  |  | 511 |     }
 | 
        
           |  |  | 512 |   | 
        
           |  |  | 513 |     protected function process_quiz_override($data) {
 | 
        
           |  |  | 514 |         global $DB;
 | 
        
           |  |  | 515 |   | 
        
           |  |  | 516 |         $data = (object)$data;
 | 
        
           |  |  | 517 |         $oldid = $data->id;
 | 
        
           |  |  | 518 |   | 
        
           |  |  | 519 |         // Based on userinfo, we'll restore user overides or no.
 | 
        
           |  |  | 520 |         $userinfo = $this->get_setting_value('userinfo');
 | 
        
           |  |  | 521 |   | 
        
           |  |  | 522 |         // Skip user overrides if we are not restoring userinfo.
 | 
        
           |  |  | 523 |         if (!$userinfo && !is_null($data->userid)) {
 | 
        
           |  |  | 524 |             return;
 | 
        
           |  |  | 525 |         }
 | 
        
           |  |  | 526 |   | 
        
           |  |  | 527 |         $data->quiz = $this->get_new_parentid('quiz');
 | 
        
           |  |  | 528 |   | 
        
           |  |  | 529 |         if ($data->userid !== null) {
 | 
        
           |  |  | 530 |             $data->userid = $this->get_mappingid('user', $data->userid);
 | 
        
           |  |  | 531 |         }
 | 
        
           |  |  | 532 |   | 
        
           |  |  | 533 |         if ($data->groupid !== null) {
 | 
        
           |  |  | 534 |             $data->groupid = $this->get_mappingid('group', $data->groupid);
 | 
        
           |  |  | 535 |         }
 | 
        
           |  |  | 536 |   | 
        
           |  |  | 537 |         // Skip if there is no user and no group data.
 | 
        
           |  |  | 538 |         if (empty($data->userid) && empty($data->groupid)) {
 | 
        
           |  |  | 539 |             return;
 | 
        
           |  |  | 540 |         }
 | 
        
           |  |  | 541 |   | 
        
           |  |  | 542 |         $data->timeopen = $this->apply_date_offset($data->timeopen);
 | 
        
           |  |  | 543 |         $data->timeclose = $this->apply_date_offset($data->timeclose);
 | 
        
           |  |  | 544 |   | 
        
           |  |  | 545 |         $newitemid = $DB->insert_record('quiz_overrides', $data);
 | 
        
           |  |  | 546 |   | 
        
           |  |  | 547 |         // Add mapping, restore of logs needs it.
 | 
        
           |  |  | 548 |         $this->set_mapping('quiz_override', $oldid, $newitemid);
 | 
        
           |  |  | 549 |     }
 | 
        
           |  |  | 550 |   | 
        
           |  |  | 551 |     protected function process_quiz_grade($data) {
 | 
        
           |  |  | 552 |         global $DB;
 | 
        
           |  |  | 553 |   | 
        
           |  |  | 554 |         $data = (object)$data;
 | 
        
           |  |  | 555 |         $oldid = $data->id;
 | 
        
           |  |  | 556 |   | 
        
           |  |  | 557 |         $data->quiz = $this->get_new_parentid('quiz');
 | 
        
           |  |  | 558 |   | 
        
           |  |  | 559 |         $data->userid = $this->get_mappingid('user', $data->userid);
 | 
        
           |  |  | 560 |         $data->grade = $data->gradeval;
 | 
        
           |  |  | 561 |   | 
        
           |  |  | 562 |         $DB->insert_record('quiz_grades', $data);
 | 
        
           |  |  | 563 |     }
 | 
        
           |  |  | 564 |   | 
        
           |  |  | 565 |     protected function process_quiz_attempt($data) {
 | 
        
           |  |  | 566 |         $data = (object)$data;
 | 
        
           |  |  | 567 |   | 
        
           |  |  | 568 |         $data->quiz = $this->get_new_parentid('quiz');
 | 
        
           |  |  | 569 |         $data->attempt = $data->attemptnum;
 | 
        
           |  |  | 570 |   | 
        
           |  |  | 571 |         // Get user mapping, return early if no mapping found for the quiz attempt.
 | 
        
           |  |  | 572 |         $olduserid = $data->userid;
 | 
        
           |  |  | 573 |         $data->userid = $this->get_mappingid('user', $olduserid, 0);
 | 
        
           |  |  | 574 |         if ($data->userid === 0) {
 | 
        
           |  |  | 575 |             $this->log('Mapped user ID not found for user ' . $olduserid . ', quiz ' . $this->get_new_parentid('quiz') .
 | 
        
           |  |  | 576 |                 ', attempt ' . $data->attempt . '. Skipping quiz attempt', backup::LOG_INFO);
 | 
        
           |  |  | 577 |   | 
        
           |  |  | 578 |             $this->currentquizattempt = null;
 | 
        
           |  |  | 579 |             return;
 | 
        
           |  |  | 580 |         }
 | 
        
           |  |  | 581 |   | 
        
           |  |  | 582 |         if (!empty($data->timecheckstate)) {
 | 
        
           |  |  | 583 |             $data->timecheckstate = $this->apply_date_offset($data->timecheckstate);
 | 
        
           |  |  | 584 |         } else {
 | 
        
           |  |  | 585 |             $data->timecheckstate = 0;
 | 
        
           |  |  | 586 |         }
 | 
        
           |  |  | 587 |   | 
        
           |  |  | 588 |         if (!isset($data->gradednotificationsenttime)) {
 | 
        
           |  |  | 589 |             // For attempts restored from old Moodle sites before this field
 | 
        
           |  |  | 590 |             // existed, we never want to send emails.
 | 
        
           |  |  | 591 |             $data->gradednotificationsenttime = $data->timefinish;
 | 
        
           |  |  | 592 |         }
 | 
        
           |  |  | 593 |   | 
        
           |  |  | 594 |         // Deals with up-grading pre-2.3 back-ups to 2.3+.
 | 
        
           |  |  | 595 |         if (!isset($data->state)) {
 | 
        
           |  |  | 596 |             if ($data->timefinish > 0) {
 | 
        
           |  |  | 597 |                 $data->state = 'finished';
 | 
        
           |  |  | 598 |             } else {
 | 
        
           |  |  | 599 |                 $data->state = 'inprogress';
 | 
        
           |  |  | 600 |             }
 | 
        
           |  |  | 601 |         }
 | 
        
           |  |  | 602 |   | 
        
           |  |  | 603 |         // The data is actually inserted into the database later in inform_new_usage_id.
 | 
        
           |  |  | 604 |         $this->currentquizattempt = clone($data);
 | 
        
           |  |  | 605 |     }
 | 
        
           |  |  | 606 |   | 
        
           |  |  | 607 |     protected function process_quiz_attempt_legacy($data) {
 | 
        
           |  |  | 608 |         global $DB;
 | 
        
           |  |  | 609 |   | 
        
           |  |  | 610 |         $this->process_quiz_attempt($data);
 | 
        
           |  |  | 611 |   | 
        
           |  |  | 612 |         $quiz = $DB->get_record('quiz', ['id' => $this->get_new_parentid('quiz')]);
 | 
        
           |  |  | 613 |         $quiz->oldquestions = $this->oldquizlayout;
 | 
        
           |  |  | 614 |         $this->process_legacy_quiz_attempt_data($data, $quiz);
 | 
        
           |  |  | 615 |     }
 | 
        
           |  |  | 616 |   | 
        
           |  |  | 617 |     protected function inform_new_usage_id($newusageid) {
 | 
        
           |  |  | 618 |         global $DB;
 | 
        
           |  |  | 619 |   | 
        
           |  |  | 620 |         $data = $this->currentquizattempt;
 | 
        
           |  |  | 621 |         if ($data === null) {
 | 
        
           |  |  | 622 |             return;
 | 
        
           |  |  | 623 |         }
 | 
        
           |  |  | 624 |   | 
        
           |  |  | 625 |         $oldid = $data->id;
 | 
        
           |  |  | 626 |         $data->uniqueid = $newusageid;
 | 
        
           |  |  | 627 |   | 
        
           |  |  | 628 |         $newitemid = $DB->insert_record('quiz_attempts', $data);
 | 
        
           |  |  | 629 |   | 
        
           |  |  | 630 |         // Save quiz_attempt->id mapping, because logs use it.
 | 
        
           |  |  | 631 |         $this->set_mapping('quiz_attempt', $oldid, $newitemid, false);
 | 
        
           |  |  | 632 |     }
 | 
        
           |  |  | 633 |   | 
        
           |  |  | 634 |     protected function after_execute() {
 | 
        
           |  |  | 635 |         global $DB;
 | 
        
           |  |  | 636 |   | 
        
           |  |  | 637 |         parent::after_execute();
 | 
        
           |  |  | 638 |         // Add quiz related files, no need to match by itemname (just internally handled context).
 | 
        
           |  |  | 639 |         $this->add_related_files('mod_quiz', 'intro', null);
 | 
        
           |  |  | 640 |         // Add feedback related files, matching by itemname = 'quiz_feedback'.
 | 
        
           |  |  | 641 |         $this->add_related_files('mod_quiz', 'feedback', 'quiz_feedback');
 | 
        
           |  |  | 642 |   | 
        
           |  |  | 643 |         if (!$this->sectioncreated) {
 | 
        
           |  |  | 644 |             $DB->insert_record('quiz_sections', [
 | 
        
           |  |  | 645 |                     'quizid' => $this->get_new_parentid('quiz'),
 | 
        
           |  |  | 646 |                     'firstslot' => 1, 'heading' => '',
 | 
        
           |  |  | 647 |                     'shufflequestions' => $this->legacyshufflequestionsoption]);
 | 
        
           |  |  | 648 |         }
 | 
        
           |  |  | 649 |     }
 | 
        
           |  |  | 650 |   | 
        
           |  |  | 651 |     protected function after_restore() {
 | 
        
           |  |  | 652 |         parent::after_restore();
 | 
        
           |  |  | 653 |         // Delete old random questions that have been converted to set references.
 | 
        
           |  |  | 654 |         foreach (array_keys($this->oldquestionids) as $oldquestionid) {
 | 
        
           |  |  | 655 |             question_delete_question($oldquestionid);
 | 
        
           |  |  | 656 |         }
 | 
        
           |  |  | 657 |     }
 | 
        
           |  |  | 658 | }
 |