/**
  * This function, executed after all the tasks in the plan
  * have been executed, will perform the recode of the
  * target glossary for the block. This must be done here
  * and not in normal execution steps because the glossary
  * may be restored after the block.
  */
 public function after_restore()
 {
     global $DB;
     // Get the blockid
     $blockid = $this->get_blockid();
     // Extract block configdata and update it to point to the new glossary
     if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
         $config = unserialize(base64_decode($configdata));
         if (!empty($config->glossary)) {
             if ($glossarymap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary', $config->glossary)) {
                 // Get glossary mapping and replace it in config
                 $config->glossary = $glossarymap->newitemid;
             } else {
                 if ($this->is_samesite()) {
                     // We are restoring on the same site, check if glossary can be used in the block in this course.
                     $glossaryid = $DB->get_field_sql("SELECT id FROM {glossary} " . "WHERE id = ? AND (course = ? OR globalglossary = 1)", [$config->glossary, $this->get_courseid()]);
                     if (!$glossaryid) {
                         unset($config->glossary);
                     }
                 } else {
                     // The block refers to a glossary not present in the backup file.
                     unset($config->glossary);
                 }
             }
             // Unset config variables that are no longer used.
             unset($config->globalglossary);
             unset($config->courseid);
             // Save updated config.
             $configdata = base64_encode(serialize($config));
             $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
         }
     }
 }
 /**
  * This function, executed after all the tasks in the plan
  * have been executed, will remove tag collection reference in case block was restored into another site.
  * Also get mapping of contextid.
  */
 public function after_restore()
 {
     global $DB;
     // Get the blockid.
     $blockid = $this->get_blockid();
     // Extract block configdata and remove tag collection reference if this is another site. Also map contextid.
     if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
         $config = unserialize(base64_decode($configdata));
         $changed = false;
         if (!empty($config->tagcoll) && $config->tagcoll > 1 && !$this->is_samesite()) {
             $config->tagcoll = 0;
             $changed = true;
         }
         if (!empty($config->ctx)) {
             if ($ctxmap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'context', $config->ctx)) {
                 $config->ctx = $ctxmap->newitemid;
             } else {
                 $config->ctx = 0;
             }
             $changed = true;
         }
         if ($changed) {
             $configdata = base64_encode(serialize($config));
             $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
         }
     }
 }
 /**
  * This function, executed after all the tasks in the plan
  * have been executed, will perform the recode of the
  * target activity for the block. This must be done here
  * and not in normal execution so we are sure everything is
  * at its finale place.
  */
 public function after_restore()
 {
     global $DB;
     // Get the blockid.
     $blockid = $this->get_blockid();
     if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
         $config = unserialize(base64_decode($configdata));
         if (!empty($config->section_id)) {
             // Get the mapping and replace it in config.
             if ($mapping = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'course_section', $config->section_id)) {
                 // Update the parent module id (the id from mdl_quiz etc...)
                 $config->section_id = $mapping->newitemid;
                 // Encode and save the config.
                 $configdata = base64_encode(serialize($config));
                 $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
                 // Arrange the replace link in the course_sections summary.
                 $newsection = $DB->get_record('course_sections', array('id' => $mapping->newitemid));
                 // Update the Side Bar section with the required values to make it work.
                 $reseturl = new moodle_url('/blocks/side_bar/reset.php?cid=' . $newsection->course);
                 $newsection->name = get_string('sidebar', 'block_side_bar');
                 $newsection->summary = get_string('sectionsummary', 'block_side_bar', (string) html_writer::link($reseturl, $reseturl));
                 $newsection->summaryformat = FORMAT_HTML;
                 $newsection->visible = true;
                 $DB->update_record('course_sections', $newsection);
             }
         }
     }
 }
 public function after_restore()
 {
     global $DB;
     $course_id = $this->get_courseid();
     $records = $DB->get_records("block_lockdownbrowser_sett", array("course" => $course_id));
     if ($records === FALSE) {
         return;
     }
     $missing_ids = 0;
     foreach ($records as $settings) {
         $old_quizid = $settings->quizid;
         if (empty($old_quizid)) {
             continue;
         }
         $quizmap = restore_dbops::get_backup_ids_record($this->get_restoreid(), "quiz", $old_quizid);
         if (empty($quizmap)) {
             $missing_ids++;
             continue;
         }
         $settings->quizid = $quizmap->newitemid;
         $DB->update_record('block_lockdownbrowser_sett', $settings);
     }
     if ($missing_ids > 0) {
         $this->get_logger()->process("Failed to restore dependency in block 'lockdownbrowser'. " . "Backup and restore will not work correctly unless you " . "include the dependent 'quiz' modules.", backup::LOG_ERROR);
     }
 }
 /**
  * This function, executed after all the tasks in the plan
  * have been executed, will perform the recode of the
  * target quiz for the block. This must be done here
  * and not in normal execution steps because the quiz
  * can be restored after the block.
  */
 public function after_restore()
 {
     global $DB;
     // Get the blockid.
     $blockid = $this->get_blockid();
     // Extract block configdata and update it to point to the new quiz.
     if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
         $config = unserialize(base64_decode($configdata));
         if (!empty($config->quizid)) {
             // Get quiz mapping and replace it in config.
             if ($quizmap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'quiz', $config->quizid)) {
                 $config->activityparent = 'quiz';
                 $config->activityparentid = $quizmap->newitemid;
                 // Set the decimal valuue as appropriate.
                 if ($config->gradeformat == 1) {
                     // This block is using percentages, do not display any decimal places.
                     $config->decimalpoints = 0;
                 } else {
                     // Get the decimal value from the corresponding quiz.
                     $config->decimalpoints = $DB->get_field('quiz', 'decimalpoints', array('id' => $config->activityparentid));
                 }
                 // Get the grade_items record to set the activitygradeitemid.
                 $info = $DB->get_record('grade_items', array('iteminstance' => $config->activityparentid, 'itemmodule' => $config->activityparent));
                 $config->activitygradeitemid = $info->id;
                 unset($config->quizid);
                 // Save the new configuration and update the record.
                 $DB->set_field('block_instances', 'configdata', base64_encode(serialize($config)), array('id' => $blockid));
                 $DB->set_field('block_instances', 'blockname', 'activity_results', array('id' => $blockid));
             }
         }
     }
 }
 protected function process_log($log, $oldctx, $context)
 {
     global $DB;
     $log = (object) $log;
     $oldid = $log->id;
     $mailedusers = explode(',', $log->mailto);
     $validusers = array();
     foreach ($mailedusers as $userid) {
         $validusers[] = $this->get_mappingid('user', $userid);
     }
     $log->courseid = $this->get_courseid();
     $log->userid = $this->get_mappingid('user', $log->userid);
     $log->mailto = implode(',', $validusers);
     $log->time = $this->apply_date_offset($log->time);
     // TODO: correctly convert alternate ids
     $log->alternateid = null;
     $newid = $DB->insert_record('block_quickmail_log', $log);
     $this->set_mapping('log', $oldid, $newid);
     foreach (array('log', 'attachment_log') as $filearea) {
         restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'block_quickmail', $filearea, $oldctx, $log->userid);
         $sql = 'UPDATE {files} SET
             itemid = :newid WHERE contextid = :ctxt AND itemid = :oldid';
         $params = array('newid' => $newid, 'oldid' => $oldid, 'ctxt' => $context->id);
         $DB->execute($sql, $params);
     }
 }
 protected function dispatch_chunk($data)
 {
     // Prepare question_category record
     if ($data['path'] == '/question_categories/question_category') {
         $info = (object) $data['tags'];
         $itemname = 'question_category';
         $itemid = $info->id;
         $parentitemid = $info->contextid;
         $this->lastcatid = $itemid;
         // Prepare question record
     } else {
         if ($data['path'] == '/question_categories/question_category/questions/question') {
             $info = (object) $data['tags'];
             $itemname = 'question';
             $itemid = $info->id;
             $parentitemid = $this->lastcatid;
             // Not question_category nor question, impossible. Throw exception.
         } else {
             throw new progressive_parser_exception('restore_questions_parser_processor_unexpected_path', $data['path']);
         }
     }
     // Only load it if needed (exist same question_categoryref itemid in table)
     if (restore_dbops::get_backup_ids_record($this->restoreid, 'question_categoryref', $this->lastcatid)) {
         restore_dbops::set_backup_ids_record($this->restoreid, $itemname, $itemid, 0, $parentitemid, $info);
     }
 }
 protected function dispatch_chunk($data)
 {
     // Received one inforef chunck, we are going to store it into backup_ids
     // table, with name = itemname + "ref" for later use
     $itemname = basename($data['path']) . 'ref';
     $itemid = $data['tags']['id'];
     restore_dbops::set_backup_ids_record($this->restoreid, $itemname, $itemid);
 }
 protected function dispatch_chunk($data)
 {
     // Received one role chunck, we are going to store it into backup_ids
     // table, with name = role
     $itemname = 'role';
     $itemid = $data['tags']['id'];
     $info = $data['tags'];
     // Only load it if needed (exist same roleref itemid in table)
     if (restore_dbops::get_backup_ids_record($this->restoreid, 'roleref', $itemid)) {
         restore_dbops::set_backup_ids_record($this->restoreid, $itemname, $itemid, 0, null, $info);
     }
 }
 protected function dispatch_chunk($data)
 {
     // Received one user chunck, we are going to store it into backup_ids
     // table, with name = user and parentid = contextid for later use
     $itemname = 'user';
     $itemid = $data['tags']['id'];
     $parentitemid = $data['tags']['contextid'];
     $info = $data['tags'];
     // Only load it if needed (exist same userref itemid in table)
     if (restore_dbops::get_backup_ids_record($this->restoreid, 'userref', $itemid)) {
         restore_dbops::set_backup_ids_record($this->restoreid, $itemname, $itemid, 0, $parentitemid, $info);
     }
 }
 /**
  *  Checks if mapped questions are exact valid, or marks them to be created
  *  
  *  @global $DB
  *  @throws moodle_exception
  */
 protected function define_execution()
 {
     global $DB;
     $restoreid = $this->get_restoreid();
     $courseid = $this->get_courseid();
     $userid = $this->task->get_userid();
     $workaround_qtypes = explode(',', get_config('block_sharing_cart', 'workaround_qtypes'));
     // @see /backup/util/dbops/restore_dbops.class.php#prechek_precheck_qbanks_by_level
     $contexts = restore_dbops::restore_get_question_banks($restoreid);
     foreach ($contexts as $contextid => $contextlevel) {
         $categories = restore_dbops::restore_get_question_categories($restoreid, $contextid);
         $canadd = false;
         if ($targetcontext = restore_dbops::restore_find_best_target_context($categories, $courseid, $contextlevel)) {
             $canadd = has_capability('moodle/question:add', $targetcontext, $userid);
         }
         foreach ($categories as $category) {
             $questions = restore_dbops::restore_get_questions($restoreid, $category->id);
             foreach ($questions as $question) {
                 if (!in_array($question->qtype, $workaround_qtypes)) {
                     continue;
                 }
                 $mapping = restore_dbops::get_backup_ids_record($restoreid, 'question', $question->id);
                 if ($mapping && $mapping->newitemid && !self::is_question_valid($question->qtype, $mapping->newitemid)) {
                     if (!$canadd) {
                         throw new moodle_exception('questioncannotberestored', 'backup', '', $question);
                     }
                     $catmapping = restore_dbops::get_backup_ids_record($restoreid, 'question_category', $category->id);
                     $matchquestions = $DB->get_records('question', array('category' => $catmapping->newitemid, 'qtype' => $question->qtype, 'stamp' => $question->stamp, 'version' => $question->version));
                     $newitemid = 0;
                     // to be created if no valid duplicate exists
                     foreach ($matchquestions as $q) {
                         if ($q->id == $mapping->newitemid) {
                             continue;
                         }
                         if (self::is_question_valid($question->qtype, $q->id)) {
                             $newitemid = $q->id;
                             // updates mapping if a valid one found
                             break;
                         }
                     }
                     $this->update_mapping($mapping, $newitemid);
                 }
             }
         }
     }
 }
 public function after_restore()
 {
     global $DB;
     // Find all the items that have a 'moduleid' but are not headings and match them up to the newly-restored activities.
     $items = $DB->get_records_select('checklist_item', 'checklist = ? AND moduleid > 0 AND itemoptional <> 2', array($this->get_activityid()));
     foreach ($items as $item) {
         $moduleid = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'course_module', $item->moduleid);
         if ($moduleid) {
             // Match up the moduleid to the restored activity module.
             $DB->set_field('checklist_item', 'moduleid', $moduleid->newitemid, array('id' => $item->id));
         } else {
             // Does not match up to a restored activity module => delete the item + associated user data.
             $DB->delete_records('checklist_check', array('item' => $item->id));
             $DB->delete_records('checklist_comment', array('itemid' => $item->id));
             $DB->delete_records('checklist_item', array('id' => $item->id));
         }
     }
 }
 /**
  * This function, executed after all the tasks in the plan
  * have been executed, will perform the recode of the
  * target quiz for the block. This must be done here
  * and not in normal execution steps because the quiz
  * can be restored after the block.
  */
 public function after_restore()
 {
     global $DB;
     // Get the blockid
     $blockid = $this->get_blockid();
     // Extract block configdata and update it to point to the new quiz
     if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
         $config = unserialize(base64_decode($configdata));
         if (!empty($config->quizid)) {
             // Get quiz mapping and replace it in config
             if ($quizmap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'quiz', $config->quizid)) {
                 $config->quizid = $quizmap->newitemid;
                 $configdata = base64_encode(serialize($config));
                 $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
             }
         }
     }
 }
Exemplo n.º 14
0
 public function test_mod_jclic_backup_restore()
 {
     global $USER, $DB, $CFG;
     require_once $CFG->dirroot . '/backup/util/includes/backup_includes.php';
     require_once $CFG->dirroot . '/backup/util/includes/restore_includes.php';
     $this->resetAfterTest(true);
     $this->setUser(2);
     // Admin user.
     // Create a course with some availability data set.
     $generator = $this->getDataGenerator();
     $course = $generator->create_course(array('format' => 'topics', 'numsections' => 3, 'enablecompletion' => COMPLETION_ENABLED), array('createsections' => true));
     $jclic = $generator->create_module('jclic', array('course' => $course->id));
     // Turn off file logging, otherwise it can't delete the file (Windows).
     $CFG->backup_file_logger_level = backup::LOG_NONE;
     // Do backup with default settings. MODE_IMPORT means it will just
     // create the directory and not zip it.
     $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
     $backupid = $bc->get_backupid();
     $bc->execute_plan();
     $bc->destroy();
     // Do restore to new course with default settings.
     $newcourseid = restore_dbops::create_new_course($course->fullname, $course->shortname . '_2', $course->category);
     $rc = new restore_controller($backupid, $newcourseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $USER->id, backup::TARGET_NEW_COURSE);
     $this->assertTrue($rc->execute_precheck());
     $rc->execute_plan();
     $rc->destroy();
     // Check settings in new course.
     $modinfo = get_fast_modinfo($newcourseid);
     $jclics = array_values($modinfo->get_instances_of('jclic'));
     $newjclic = new jclic(context_module::instance($jclics[0]->id), false, false);
     $newjclicmodule = $newjclic->get_instance();
     $this->assertNotEmpty($newjclic);
     $jclic = new jclic(context_module::instance($jclic->cmid), false, false);
     $jclicmodule = $jclic->get_instance();
     $fields = (array) $jclicmodule;
     unset($fields['id']);
     unset($fields['course']);
     foreach ($fields as $key => $unused) {
         $this->assertEquals($newjclicmodule->{$key}, $jclicmodule->{$key}, "Failed on field {$key}");
     }
     // Avoid errors...
     ini_set('max_execution_time', 0);
 }
 /**
  * Translates the backed up configuration data for the target course modules.
  *
  * @global type $DB
  */
 public function after_restore()
 {
     global $DB;
     $prefixes = array('monitor_', 'date_time_', 'action_', 'locked_');
     // Get the blockid.
     $id = $this->get_blockid();
     // Get restored course id.
     $courseid = $this->get_courseid();
     if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $id))) {
         $config = (array) unserialize(base64_decode($configdata));
         $newconfig = $config;
         // Filter module related config information.
         foreach ($newconfig as $key => $value) {
             foreach ($prefixes as $prefix) {
                 if (substr($key, 0, strlen($prefix)) === $prefix) {
                     unset($newconfig[$key]);
                 }
             }
         }
         // Translate the old config information to the target course values.
         foreach ($config as $key => $value) {
             $matches = array();
             preg_match('/monitor_(\\D+)(\\d+)/', $key, $matches);
             if (!empty($matches)) {
                 $module = $matches[1];
                 $instance = $matches[2];
                 // Find the mapped instance ID.
                 if ($newinstance = restore_dbops::get_backup_ids_record($this->get_restoreid(), $module, $instance)) {
                     $newinstanceid = $newinstance->newitemid;
                     // Translate new instance values from old IDs.
                     foreach ($prefixes as $prefix) {
                         if (isset($config["{$prefix}{$module}{$instance}"])) {
                             $newconfig["{$prefix}{$module}{$newinstanceid}"] = $config["{$prefix}{$module}{$instance}"];
                         }
                     }
                 }
             }
         }
         // Save everything back to DB.
         $configdata = base64_encode(serialize((object) $newconfig));
         $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $id));
     }
 }
Exemplo n.º 16
0
/**
 * Roll over an existing Moodle course into a new one using a customized backup
 * and restore routine
 *
 * @param int $courseid Id of the course we are copying
 * @param int $categoryid
 * @return int|boolean Id of the newly created course
 */
function course_rollover($courseid, $categoryid = null)
{
    global $DB;
    if ($course = $DB->get_record('course', array('id' => $courseid))) {
        //figure out the category
        if ($categoryid === null) {
            $categoryid = $course->category;
        }
        //make sure the category is valid
        if (!$DB->record_exists('course_categories', array('id' => $categoryid))) {
            //invalid category
            return false;
        }
        //perform backup without including user info
        $controller = new rollover_backup_controller($courseid);
        $controller->get_plan()->get_setting('users')->set_value(false);
        $controller->execute_plan();
        //get directory name for use in restore
        $backupid = $controller->get_backupid();
        //start a database transaction to make sure restore is atomic, etc
        $transaction = $DB->start_delegated_transaction();
        //create the new course
        $result = restore_dbops::create_new_course($course->fullname, $course->shortname, $categoryid);
        //restore the content into it within the current transaction without including user information
        $controller = new rollover_restore_controller($backupid, $result);
        $controller->get_plan()->get_setting('users')->set_value(false);
        $controller->execute_precheck();
        $controller->execute_plan();
        //make sure the sort order is defined as expected
        fix_course_sortorder();
        try {
            //try to finalize
            $transaction->allow_commit();
        } catch (dml_transaction_exception $e) {
            //failure
            $result = false;
        }
        return $result;
    } else {
        //invalid course specified
        return false;
    }
}
 /**
  * Translates the backed up configuration data for the target course modules
  *
  * @global type $DB
  */
 public function after_restore()
 {
     global $DB;
     // Get the blockid
     $id = $this->get_blockid();
     //Restored course id
     $courseid = $this->get_courseid();
     if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $id))) {
         $config = (array) unserialize(base64_decode($configdata));
         // Translate the old config information to the target course values
         foreach ($config as $key => $value) {
             $matches = array();
             preg_match('/monitor_(\\D+)(\\d+)/', $key, $matches);
             if ($value == 1 && !empty($matches)) {
                 $module = $matches[1];
                 $instance = $matches[2];
                 // Find a matching module in the target course
                 if ($cm = get_coursemodule_from_instance($module, $instance)) {
                     // Get new cm and instance
                     $newitem = restore_dbops::get_backup_ids_record($this->get_restoreid(), "course_module", $cm->id);
                     $newcm = get_coursemodule_from_id($module, $newitem->newitemid);
                     $newinstance = $newcm->instance;
                     // Set new config
                     $config["monitor_{$module}{$newinstance}"] = $config["monitor_{$module}{$instance}"];
                     $config["locked_{$module}{$newinstance}"] = $config["locked_{$module}{$instance}"];
                     $config["date_time_{$module}{$newinstance}"] = $config["date_time_{$module}{$instance}"];
                     $config["action_{$module}{$newinstance}"] = $config["action_{$module}{$instance}"];
                     // Unset old config
                     unset($config["monitor_{$module}{$instance}"]);
                     unset($config["locked_{$module}{$instance}"]);
                     unset($config["date_time_{$module}{$instance}"]);
                     unset($config["action_{$module}{$instance}"]);
                 }
             }
         }
         // Save everything back to DB
         $configdata = base64_encode(serialize((object) $config));
         $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $id));
     }
 }
 public function update_after_restore($restoreid, $courseid, \base_logger $logger, $name)
 {
     global $DB;
     if (!$this->roleid) {
         // If using 'same as activity' option, no need to change it.
         return false;
     }
     $rec = \restore_dbops::get_backup_ids_record($restoreid, 'role', $this->roleid);
     if (!$rec || !$rec->newitemid) {
         // If we are on the same course (e.g. duplicate) then we can just
         // use the existing one.
         if ($DB->record_exists('roles', array('id' => $this->roleid, 'courseid' => $courseid))) {
             return false;
         }
         // Otherwise it's a warning.
         $this->roleid = -1;
         $logger->process('Restored item (' . $name . ') has availability condition on grouping that was not restored', \backup::LOG_WARNING);
     } else {
         $this->roleid = (int) $rec->newitemid;
     }
     return true;
 }
 /**
  * This function, executed after all the tasks in the plan
  * have been executed, will perform the recode of the
  * target activity for the block. This must be done here
  * and not in normal execution steps because the activity
  * can be restored after the block.
  */
 public function after_restore()
 {
     global $DB;
     // Get the blockid.
     $blockid = $this->get_blockid();
     if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
         $config = unserialize(base64_decode($configdata));
         if (!empty($config->activityparentid)) {
             // Get the mapping and replace it in config.
             if ($mapping = restore_dbops::get_backup_ids_record($this->get_restoreid(), $config->activityparent, $config->activityparentid)) {
                 // Update the parent module id (the id from mdl_quiz etc...)
                 $config->activityparentid = $mapping->newitemid;
                 // Get the grade_items record to update the activitygradeitemid.
                 $info = $DB->get_record('grade_items', array('iteminstance' => $config->activityparentid, 'itemmodule' => $config->activityparent));
                 // Update the activitygradeitemid the id from the grade_items table.
                 $config->activitygradeitemid = $info->id;
                 // Encode and save the config.
                 $configdata = base64_encode(serialize($config));
                 $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
             }
         }
     }
 }
 /**
  * This function, executed after all the tasks in the plan
  * have been executed, will perform the recode of the
  * target glossary for the block. This must be done here
  * and not in normal execution steps because the glossary
  * may be restored after the block.
  */
 public function after_restore()
 {
     global $DB;
     // Get the blockid
     $blockid = $this->get_blockid();
     // Extract block configdata and update it to point to the new glossary
     if ($configdata = $DB->get_field('block_instances', 'configdata', array('id' => $blockid))) {
         $config = unserialize(base64_decode($configdata));
         if (!empty($config->glossary)) {
             // Get glossary mapping and replace it in config
             if ($glossarymap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary', $config->glossary)) {
                 $mappedglossary = $DB->get_record('glossary', array('id' => $glossarymap->newitemid), 'id,course,globalglossary', MUST_EXIST);
                 $config->glossary = $mappedglossary->id;
                 $config->courseid = $mappedglossary->course;
                 $config->globalglossary = $mappedglossary->globalglossary;
                 $configdata = base64_encode(serialize($config));
                 $DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
             } else {
                 // The block refers to a glossary not present in the backup file.
                 $DB->set_field('block_instances', 'configdata', '', array('id' => $blockid));
             }
         }
     }
 }
Exemplo n.º 21
0
 /**
  * Send the question type specific files to a new context.
  *
  * @param text            $qtype The qtype name to send.
  * @param int             $oldctxid Old context id.
  * @param int             $newctxid New context id.
  * @param \core\progress  $progress Progress object to use.
  */
 private function send_qtype_files($qtype, $oldctxid, $newctxid, $progress)
 {
     if (!isset($this->qtypecomponentscache[$qtype])) {
         $this->qtypecomponentscache[$qtype] = backup_qtype_plugin::get_components_and_fileareas($qtype);
     }
     $components = $this->qtypecomponentscache[$qtype];
     foreach ($components as $component => $fileareas) {
         foreach ($fileareas as $filearea => $mapping) {
             restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component, $filearea, $oldctxid, $this->task->get_userid(), $mapping, null, $newctxid, true, $progress);
         }
     }
 }
Exemplo n.º 22
0
 /**
  * Add all the existing file, given their component and filearea and one backup_ids itemname to match with
  */
 public function add_related_files($component, $filearea, $mappingitemname, $filesctxid = null, $olditemid = null)
 {
     // If the current progress object is set up and ready to receive
     // indeterminate progress, then use it, otherwise don't. (This check is
     // just in case this function is ever called from somewhere not within
     // the execute() method here, which does set up progress like this.)
     $progress = $this->get_task()->get_progress();
     if (!$progress->is_in_progress_section() || $progress->get_current_max() !== \core\progress\base::INDETERMINATE) {
         $progress = null;
     }
     $filesctxid = is_null($filesctxid) ? $this->task->get_old_contextid() : $filesctxid;
     $results = restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component, $filearea, $filesctxid, $this->task->get_userid(), $mappingitemname, $olditemid, null, false, $progress);
     $resultstoadd = array();
     foreach ($results as $result) {
         $this->log($result->message, $result->level);
         $resultstoadd[$result->code] = true;
     }
     $this->task->add_result($resultstoadd);
 }
Exemplo n.º 23
0
    /**
     * Imports a course
     *
     * @param int $importfrom The id of the course we are importing from
     * @param int $importto The id of the course we are importing to
     * @param bool $deletecontent Whether to delete the course we are importing to content
     * @param array $options List of backup options
     * @return null
     * @since Moodle 2.4
     */
    public static function import_course($importfrom, $importto, $deletecontent = 0, $options = array()) {
        global $CFG, $USER, $DB;
        require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
        require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');

        // Parameter validation.
        $params = self::validate_parameters(
            self::import_course_parameters(),
            array(
                'importfrom' => $importfrom,
                'importto' => $importto,
                'deletecontent' => $deletecontent,
                'options' => $options
            )
        );

        if ($params['deletecontent'] !== 0 and $params['deletecontent'] !== 1) {
            throw new moodle_exception('invalidextparam', 'webservice', '', $params['deletecontent']);
        }

        // Context validation.

        if (! ($importfrom = $DB->get_record('course', array('id'=>$params['importfrom'])))) {
            throw new moodle_exception('invalidcourseid', 'error');
        }

        if (! ($importto = $DB->get_record('course', array('id'=>$params['importto'])))) {
            throw new moodle_exception('invalidcourseid', 'error');
        }

        $importfromcontext = context_course::instance($importfrom->id);
        self::validate_context($importfromcontext);

        $importtocontext = context_course::instance($importto->id);
        self::validate_context($importtocontext);

        $backupdefaults = array(
            'activities' => 1,
            'blocks' => 1,
            'filters' => 1
        );

        $backupsettings = array();

        // Check for backup and restore options.
        if (!empty($params['options'])) {
            foreach ($params['options'] as $option) {

                // Strict check for a correct value (allways 1 or 0, true or false).
                $value = clean_param($option['value'], PARAM_INT);

                if ($value !== 0 and $value !== 1) {
                    throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
                }

                if (!isset($backupdefaults[$option['name']])) {
                    throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
                }

                $backupsettings[$option['name']] = $value;
            }
        }

        // Capability checking.

        require_capability('moodle/backup:backuptargetimport', $importfromcontext);
        require_capability('moodle/restore:restoretargetimport', $importtocontext);

        $bc = new backup_controller(backup::TYPE_1COURSE, $importfrom->id, backup::FORMAT_MOODLE,
                backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);

        foreach ($backupsettings as $name => $value) {
            $bc->get_plan()->get_setting($name)->set_value($value);
        }

        $backupid       = $bc->get_backupid();
        $backupbasepath = $bc->get_plan()->get_basepath();

        $bc->execute_plan();
        $bc->destroy();

        // Restore the backup immediately.

        // Check if we must delete the contents of the destination course.
        if ($params['deletecontent']) {
            $restoretarget = backup::TARGET_EXISTING_DELETING;
        } else {
            $restoretarget = backup::TARGET_EXISTING_ADDING;
        }

        $rc = new restore_controller($backupid, $importto->id,
                backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, $restoretarget);

        foreach ($backupsettings as $name => $value) {
            $rc->get_plan()->get_setting($name)->set_value($value);
        }

        if (!$rc->execute_precheck()) {
            $precheckresults = $rc->get_precheck_results();
            if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
                if (empty($CFG->keeptempdirectoriesonbackup)) {
                    fulldelete($backupbasepath);
                }

                $errorinfo = '';

                foreach ($precheckresults['errors'] as $error) {
                    $errorinfo .= $error;
                }

                if (array_key_exists('warnings', $precheckresults)) {
                    foreach ($precheckresults['warnings'] as $warning) {
                        $errorinfo .= $warning;
                    }
                }

                throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
            }
        } else {
            if ($restoretarget == backup::TARGET_EXISTING_DELETING) {
                restore_dbops::delete_course_content($importto->id);
            }
        }

        $rc->execute_plan();
        $rc->destroy();

        if (empty($CFG->keeptempdirectoriesonbackup)) {
            fulldelete($backupbasepath);
        }

        return null;
    }
Exemplo n.º 24
0
 /**
  * Processes the destination stage.
  * @return bool
  * @throws coding_exception
  * @throws restore_ui_exception
  */
 public function process()
 {
     global $CFG, $DB;
     if (!file_exists("{$CFG->tempdir}/backup/" . $this->filepath) || !is_dir("{$CFG->tempdir}/backup/" . $this->filepath)) {
         throw new restore_ui_exception('invalidrestorepath');
     }
     if (optional_param('searchcourses', false, PARAM_BOOL)) {
         return false;
     }
     $this->target = optional_param('target', backup::TARGET_NEW_COURSE, PARAM_INT);
     $targetid = optional_param('targetid', null, PARAM_INT);
     if (!is_null($this->target) && !is_null($targetid) && confirm_sesskey()) {
         if ($this->target == backup::TARGET_NEW_COURSE) {
             list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'), get_string('restoringcourseshortname', 'backup'));
             $this->courseid = restore_dbops::create_new_course($fullname, $shortname, $targetid);
         } else {
             $this->courseid = $targetid;
         }
         return $DB->record_exists('course', array('id' => $this->courseid));
     }
     return false;
 }
Exemplo n.º 25
0
    protected function define_execution() {
        global $DB;

        // Let's process only created questions
        $questionsrs = $DB->get_recordset_sql("SELECT bi.itemid, bi.newitemid, bi.parentitemid, q.qtype
                                               FROM {backup_ids_temp} bi
                                               JOIN {question} q ON q.id = bi.newitemid
                                              WHERE bi.backupid = ?
                                                AND bi.itemname = 'question_created'", array($this->get_restoreid()));
        foreach ($questionsrs as $question) {
            // Get question_category mapping, it contains the target context for the question
            if (!$qcatmapping = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'question_category', $question->parentitemid)) {
                // Something went really wrong, cannot find the question_category for the question
                debugging('Error fetching target context for question', DEBUG_DEVELOPER);
                continue;
            }
            // Calculate source and target contexts
            $oldctxid = $qcatmapping->info->contextid;
            $newctxid = $qcatmapping->parentitemid;

            // Add common question files (question and question_answer ones)
            restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'questiontext',
                                              $oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true);
            restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'generalfeedback',
                                              $oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true);
            restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answer',
                                              $oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true);
            restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answerfeedback',
                                              $oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true);
            restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'hint',
                                              $oldctxid, $this->task->get_userid(), 'question_hint', null, $newctxid, true);
            // Add qtype dependent files
            $components = backup_qtype_plugin::get_components_and_fileareas($question->qtype);
            foreach ($components as $component => $fileareas) {
                foreach ($fileareas as $filearea => $mapping) {
                    // Use itemid only if mapping is question_created
                    $itemid = ($mapping == 'question_created') ? $question->itemid : null;
                    restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component, $filearea,
                                                      $oldctxid, $this->task->get_userid(), $mapping, $itemid, $newctxid, true);
                }
            }
        }
        $questionsrs->close();
    }
Exemplo n.º 26
0
 /**
  * Backs a course up and restores it.
  *
  * @param stdClass $course Course object to backup
  * @param int $newdate If non-zero, specifies custom date for new course
  * @return int ID of newly restored course
  */
 protected function backup_and_restore($course, $newdate = 0)
 {
     global $USER, $CFG;
     // Turn off file logging, otherwise it can't delete the file (Windows).
     $CFG->backup_file_logger_level = backup::LOG_NONE;
     // Do backup with default settings. MODE_IMPORT means it will just
     // create the directory and not zip it.
     $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
     $backupid = $bc->get_backupid();
     $bc->execute_plan();
     $bc->destroy();
     // Do restore to new course with default settings.
     $newcourseid = restore_dbops::create_new_course($course->fullname, $course->shortname . '_2', $course->category);
     $rc = new restore_controller($backupid, $newcourseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $USER->id, backup::TARGET_NEW_COURSE);
     if ($newdate) {
         $rc->get_plan()->get_setting('course_startdate')->set_value($newdate);
     }
     $this->assertTrue($rc->execute_precheck());
     $rc->execute_plan();
     $rc->destroy();
     return $newcourseid;
 }
Exemplo n.º 27
0
<?php

define('CLI_SCRIPT', true);
chdir('/var/www/ae.ket.org');
require_once 'config.php';
require_once $CFG->dirroot . '/backup/util/includes/restore_includes.php';
// Transaction
$transaction = $DB->start_delegated_transaction();
// Create new course
$folder = '9706ff11ee909cc426e66fff74926faa';
// as found in: $CFG->dataroot . '/temp/backup/'
$categoryid = 1;
// e.g. 1 == Miscellaneous
$user_doing_the_restore = 4;
// e.g. 2 == admin
$courseid = restore_dbops::create_new_course('Z', 'Z', $categoryid);
// Restore backup into course
$controller = new restore_controller($folder, $courseid, backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $user_doing_the_restore, backup::TARGET_NEW_COURSE);
$controller->execute_precheck();
$controller->execute_plan();
// Commit
$transaction->allow_commit();
 public function after_restore()
 {
     // Do something at end of restore.
     global $DB;
     // Get the blockid.
     $gameid = $this->get_activityid();
     // Extract Game configdata and update it to point to the new glossary.
     $rec = $DB->get_record_select('game', 'id=' . $gameid, null, 'id,quizid,glossaryid,glossarycategoryid,questioncategoryid,bookid,glossaryid2,glossarycategoryid2');
     $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'quiz', $rec->quizid);
     if ($ret != false) {
         $rec->quizid = $ret->newitemid;
     }
     $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary', $rec->glossaryid);
     if ($ret != false) {
         $rec->glossaryid = $ret->newitemid;
     }
     $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary_categories', $rec->glossarycategoryid);
     if ($ret != false) {
         $rec->glossarycategoryid = $ret->newitemid;
     }
     $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'question_categories', $rec->questioncategoryid);
     if ($ret != false) {
         $rec->questioncategoryid = $ret->newitemid;
     }
     $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'book', $rec->bookid);
     if ($ret != false) {
         $rec->bookid = $ret->newitemid;
     }
     $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary', $rec->glossaryid2);
     if ($ret != false) {
         $rec->glossaryid2 = $ret->newitemid;
     }
     $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary_categories', $rec->glossarycategoryid);
     if ($ret != false) {
         $rec->glossarycategoryid = $ret->newitemid;
     }
     $DB->update_record('game', $rec);
     // Read game_repetitions.
     $recs = $DB->get_records_select('game_repetitions', 'gameid=' . $gameid, null, '', 'id,questionid,glossaryentryid');
     if ($recs != false) {
         foreach ($recs as $rec) {
             $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'question', $rec->questionid);
             if ($ret != false) {
                 $rec->questionid = $ret->newitemid;
             }
             $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary_entry', $rec->glossaryentryid);
             if ($ret != false) {
                 $rec->glossaryentryid = $ret->newitemid;
             }
             $DB->update_record('game_repetitions', $rec);
         }
     }
     // Read game_queries.
     $recs = $DB->get_records_select('game_queries', 'gameid=' . $gameid, null, '', 'id,questionid,glossaryentryid,answerid');
     if ($recs != false) {
         foreach ($recs as $rec) {
             $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'question', $rec->questionid);
             if ($ret != false) {
                 $rec->questionid = $ret->newitemid;
             }
             $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary_entry', $rec->glossaryentryid);
             if ($ret != false) {
                 $rec->glossaryentryid = $ret->newitemid;
             }
             $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'question_answers', $rec->glossaryentryid);
             if ($ret != false) {
                 $rec->answerid = $ret->newitemid;
             }
             $DB->update_record('game_queries', $rec);
         }
     }
     // Read bookquiz.
     $recs = $DB->get_records_select('game_bookquiz', 'id=' . $gameid, null, '', 'id,lastchapterid');
     if ($recs != false) {
         foreach ($recs as $rec) {
             $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'book_chapters', $rec->lastchapterid);
             if ($ret != false) {
                 $rec->lastchapterid = $ret->newitemid;
             }
             $DB->update_record('game_bookquiz', $rec);
         }
     }
     // Read bookquiz_chapters.
     $sql = "SELECT gbc.* " . "FROM {game_bookquiz_chapters} gbc LEFT JOIN {game_attempts} a ON gbc.attemptid = a.id" . " WHERE a.gameid={$gameid}";
     $recs = $DB->get_records_sql($sql);
     if ($recs != false) {
         foreach ($recs as $rec) {
             $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'book_chapters', $rec->chapterid);
             if ($ret != false) {
                 $rec->chapterid = $ret->newitemid;
             }
             $DB->update_record('game_bookquiz_chapter', $rec);
         }
     }
     // Read bookquiz_questions.
     $recs = $DB->get_records_select('game_bookquiz_questions', 'id=' . $gameid, null, '', 'id,chapterid,questioncategoryid');
     if ($recs != false) {
         foreach ($recs as $rec) {
             $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'book_chapters', $rec->chapterid);
             if ($ret != false) {
                 $rec->chapterid = $ret->newitemid;
             }
             $ret = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'book_chapters', $rec->questioncategoryid);
             if ($ret != false) {
                 $rec->questioncategoryid = $ret->newitemid;
             }
             $DB->update_record('game_bookquiz_questions', $rec);
         }
     }
 }
Exemplo n.º 29
0
    /**
     * Restores a given stash stored previously by {@link self::set_stash()}
     *
     * @param string $stashname name of the stash
     * @param int $itemid optional id for multiple infos within the same stashname
     * @throws moodle1_convert_empty_storage_exception if the info has not been stashed previously
     * @return mixed stashed data
     */
    public function get_stash($stashname, $itemid = 0) {

        $record = restore_dbops::get_backup_ids_record($this->get_id(), $stashname, $itemid);

        if (empty($record)) {
            throw new moodle1_convert_empty_storage_exception('required_not_stashed_data', array($stashname, $itemid));
        } else {
            return $record->info;
        }
    }
 /**
  * Entry point for all the prechecks to be performed before restore
  *
  * Returns empty array or warnings/errors array
  */
 public static function execute_prechecks(restore_controller $controller, $droptemptablesafter = false)
 {
     global $CFG;
     $errors = array();
     $warnings = array();
     // Some handy vars to be used along the prechecks
     $samesite = $controller->is_samesite();
     $restoreusers = $controller->get_plan()->get_setting('users')->get_value();
     $hasmnetusers = (int) $controller->get_info()->mnet_remoteusers;
     $restoreid = $controller->get_restoreid();
     $courseid = $controller->get_courseid();
     $userid = $controller->get_userid();
     $rolemappings = $controller->get_info()->role_mappings;
     $progress = $controller->get_progress();
     // Start tracking progress. There are currently 8 major steps, corresponding
     // to $majorstep++ lines in this code; we keep track of the total so as to
     // verify that it's still correct. If you add a major step, you need to change
     // the total here.
     $majorstep = 1;
     $majorsteps = 8;
     $progress->start_progress('Carrying out pre-restore checks', $majorsteps);
     // Load all the included tasks to look for inforef.xml files
     $inforeffiles = array();
     $tasks = restore_dbops::get_included_tasks($restoreid);
     $progress->start_progress('Listing inforef files', count($tasks));
     $minorstep = 1;
     foreach ($tasks as $task) {
         // Add the inforef.xml file if exists
         $inforefpath = $task->get_taskbasepath() . '/inforef.xml';
         if (file_exists($inforefpath)) {
             $inforeffiles[] = $inforefpath;
         }
         $progress->progress($minorstep++);
     }
     $progress->end_progress();
     $progress->progress($majorstep++);
     // Create temp tables
     restore_controller_dbops::create_restore_temp_tables($controller->get_restoreid());
     // Check we are restoring one backup >= $min20version (very first ok ever)
     $min20version = 2010072300;
     if ($controller->get_info()->backup_version < $min20version) {
         $message = new stdclass();
         $message->backup = $controller->get_info()->backup_version;
         $message->min = $min20version;
         $errors[] = get_string('errorminbackup20version', 'backup', $message);
     }
     // Compare Moodle's versions
     if ($CFG->version < $controller->get_info()->moodle_version) {
         $message = new stdclass();
         $message->serverversion = $CFG->version;
         $message->serverrelease = $CFG->release;
         $message->backupversion = $controller->get_info()->moodle_version;
         $message->backuprelease = $controller->get_info()->moodle_release;
         $warnings[] = get_string('noticenewerbackup', '', $message);
     }
     // Error if restoring over frontpage
     // TODO: Review the whole restore process in order to transform this into one warning (see 1.9)
     if ($controller->get_courseid() == SITEID) {
         $errors[] = get_string('errorrestorefrontpage', 'backup');
     }
     // If restoring to different site and restoring users and backup has mnet users warn/error
     if (!$samesite && $restoreusers && $hasmnetusers) {
         // User is admin (can create users at sysctx), warn
         if (has_capability('moodle/user:create', context_system::instance(), $controller->get_userid())) {
             $warnings[] = get_string('mnetrestore_extusers_admin', 'admin');
             // User not admin
         } else {
             $errors[] = get_string('mnetrestore_extusers_noadmin', 'admin');
         }
     }
     // Load all the inforef files, we are going to need them
     $progress->start_progress('Loading temporary IDs', count($inforeffiles));
     $minorstep = 1;
     foreach ($inforeffiles as $inforeffile) {
         // Load each inforef file to temp_ids.
         restore_dbops::load_inforef_to_tempids($restoreid, $inforeffile, $progress);
         $progress->progress($minorstep++);
     }
     $progress->end_progress();
     $progress->progress($majorstep++);
     // If restoring users, check we are able to create all them
     if ($restoreusers) {
         $file = $controller->get_plan()->get_basepath() . '/users.xml';
         // Load needed users to temp_ids.
         restore_dbops::load_users_to_tempids($restoreid, $file, $progress);
         $progress->progress($majorstep++);
         if ($problems = restore_dbops::precheck_included_users($restoreid, $courseid, $userid, $samesite, $progress)) {
             $errors = array_merge($errors, $problems);
         }
     } else {
         // To ensure consistent number of steps in progress tracking,
         // mark progress even though we didn't do anything.
         $progress->progress($majorstep++);
     }
     $progress->progress($majorstep++);
     // Note: restore won't create roles at all. Only mapping/skip!
     $file = $controller->get_plan()->get_basepath() . '/roles.xml';
     restore_dbops::load_roles_to_tempids($restoreid, $file);
     // Load needed roles to temp_ids
     if ($problems = restore_dbops::precheck_included_roles($restoreid, $courseid, $userid, $samesite, $rolemappings)) {
         $errors = array_key_exists('errors', $problems) ? array_merge($errors, $problems['errors']) : $errors;
         $warnings = array_key_exists('warnings', $problems) ? array_merge($warnings, $problems['warnings']) : $warnings;
     }
     $progress->progress($majorstep++);
     // Check we are able to restore and the categories and questions
     $file = $controller->get_plan()->get_basepath() . '/questions.xml';
     restore_dbops::load_categories_and_questions_to_tempids($restoreid, $file);
     if ($problems = restore_dbops::precheck_categories_and_questions($restoreid, $courseid, $userid, $samesite)) {
         $errors = array_key_exists('errors', $problems) ? array_merge($errors, $problems['errors']) : $errors;
         $warnings = array_key_exists('warnings', $problems) ? array_merge($warnings, $problems['warnings']) : $warnings;
     }
     $progress->progress($majorstep++);
     // Prepare results.
     $results = array();
     if (!empty($errors)) {
         $results['errors'] = $errors;
     }
     if (!empty($warnings)) {
         $results['warnings'] = $warnings;
     }
     // Warnings/errors detected or want to do so explicitly, drop temp tables
     if (!empty($results) || $droptemptablesafter) {
         restore_controller_dbops::drop_restore_temp_tables($controller->get_restoreid());
     }
     // Finish progress and check we got the initial number of steps right.
     $progress->progress($majorstep++);
     if ($majorstep != $majorsteps) {
         throw new coding_exception('Progress step count wrong: ' . $majorstep);
     }
     $progress->end_progress();
     return $results;
 }