| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 4 | //
 | 
        
           |  |  | 5 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 6 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 7 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 8 | // (at your option) any later version.
 | 
        
           |  |  | 9 | //
 | 
        
           |  |  | 10 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 13 | // GNU General Public License for more details.
 | 
        
           |  |  | 14 | //
 | 
        
           |  |  | 15 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 16 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 17 |   | 
        
           |  |  | 18 | /**
 | 
        
           |  |  | 19 |  * @package    moodlecore
 | 
        
           |  |  | 20 |  * @subpackage backup-helper
 | 
        
           |  |  | 21 |  * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
 | 
        
           |  |  | 22 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 23 |  */
 | 
        
           |  |  | 24 |   | 
        
           |  |  | 25 | /**
 | 
        
           |  |  | 26 |  * Non instantiable helper class providing support for restore prechecks
 | 
        
           |  |  | 27 |  *
 | 
        
           |  |  | 28 |  * This class contains various prechecks to be performed before executing
 | 
        
           |  |  | 29 |  * the restore plan. Its entry point is execute_prechecks() that will
 | 
        
           |  |  | 30 |  * call various stuff. At the end, it will return one array(), if empty
 | 
        
           |  |  | 31 |  * all the prechecks have passed ok. If not empty, you'll find 1/2 elements
 | 
        
           |  |  | 32 |  * in the array, warnings and errors, each one containing one description
 | 
        
           |  |  | 33 |  * of the problem. Warnings aren't stoppers so the restore execution can
 | 
        
           |  |  | 34 |  * continue after displaying them. In the other side, if errors are returned
 | 
        
           |  |  | 35 |  * then restore execution cannot continue
 | 
        
           |  |  | 36 |  *
 | 
        
           |  |  | 37 |  * TODO: Finish phpdocs
 | 
        
           |  |  | 38 |  */
 | 
        
           |  |  | 39 | abstract class restore_prechecks_helper {
 | 
        
           |  |  | 40 |   | 
        
           |  |  | 41 |     /**
 | 
        
           |  |  | 42 |      * Entry point for all the prechecks to be performed before restore
 | 
        
           |  |  | 43 |      *
 | 
        
           |  |  | 44 |      * Returns empty array or warnings/errors array
 | 
        
           |  |  | 45 |      */
 | 
        
           |  |  | 46 |     public static function execute_prechecks(restore_controller $controller, $droptemptablesafter = false) {
 | 
        
           |  |  | 47 |         global $CFG;
 | 
        
           |  |  | 48 |   | 
        
           |  |  | 49 |         $errors = array();
 | 
        
           |  |  | 50 |         $warnings = array();
 | 
        
           |  |  | 51 |   | 
        
           |  |  | 52 |         // Some handy vars to be used along the prechecks
 | 
        
           |  |  | 53 |         $samesite = $controller->is_samesite();
 | 
        
           |  |  | 54 |         $restoreusers = $controller->get_plan()->get_setting('users')->get_value();
 | 
        
           |  |  | 55 |         $hasmnetusers = (int)$controller->get_info()->mnet_remoteusers;
 | 
        
           |  |  | 56 |         $restoreid = $controller->get_restoreid();
 | 
        
           |  |  | 57 |         $courseid = $controller->get_courseid();
 | 
        
           |  |  | 58 |         $userid = $controller->get_userid();
 | 
        
           |  |  | 59 |         $rolemappings = $controller->get_info()->role_mappings;
 | 
        
           |  |  | 60 |         $progress = $controller->get_progress();
 | 
        
           |  |  | 61 |   | 
        
           |  |  | 62 |         // Start tracking progress. There are currently 8 major steps, corresponding
 | 
        
           |  |  | 63 |         // to $majorstep++ lines in this code; we keep track of the total so as to
 | 
        
           |  |  | 64 |         // verify that it's still correct. If you add a major step, you need to change
 | 
        
           |  |  | 65 |         // the total here.
 | 
        
           |  |  | 66 |         $majorstep = 1;
 | 
        
           |  |  | 67 |         $majorsteps = 8;
 | 
        
           |  |  | 68 |         $progress->start_progress('Carrying out pre-restore checks', $majorsteps);
 | 
        
           |  |  | 69 |   | 
        
           |  |  | 70 |         // Load all the included tasks to look for inforef.xml files
 | 
        
           |  |  | 71 |         $inforeffiles = array();
 | 
        
           |  |  | 72 |         $tasks = restore_dbops::get_included_tasks($restoreid);
 | 
        
           |  |  | 73 |         $progress->start_progress('Listing inforef files', count($tasks));
 | 
        
           |  |  | 74 |         $minorstep = 1;
 | 
        
           |  |  | 75 |         foreach ($tasks as $task) {
 | 
        
           |  |  | 76 |             // Add the inforef.xml file if exists
 | 
        
           |  |  | 77 |             $inforefpath = $task->get_taskbasepath() . '/inforef.xml';
 | 
        
           |  |  | 78 |             if (file_exists($inforefpath)) {
 | 
        
           |  |  | 79 |                 $inforeffiles[] = $inforefpath;
 | 
        
           |  |  | 80 |             }
 | 
        
           |  |  | 81 |             $progress->progress($minorstep++);
 | 
        
           |  |  | 82 |         }
 | 
        
           |  |  | 83 |         $progress->end_progress();
 | 
        
           |  |  | 84 |         $progress->progress($majorstep++);
 | 
        
           |  |  | 85 |   | 
        
           |  |  | 86 |         // Create temp tables
 | 
        
           |  |  | 87 |         restore_controller_dbops::create_restore_temp_tables($controller->get_restoreid());
 | 
        
           |  |  | 88 |   | 
        
           |  |  | 89 |         // Check we are restoring one backup >= $min20version (very first ok ever)
 | 
        
           |  |  | 90 |         $min20version = 2010072300;
 | 
        
           |  |  | 91 |         if ($controller->get_info()->backup_version < $min20version) {
 | 
        
           |  |  | 92 |             $message = new stdclass();
 | 
        
           |  |  | 93 |             $message->backup = $controller->get_info()->backup_version;
 | 
        
           |  |  | 94 |             $message->min    = $min20version;
 | 
        
           |  |  | 95 |             $errors[] = get_string('errorminbackup20version', 'backup', $message);
 | 
        
           |  |  | 96 |         }
 | 
        
           |  |  | 97 |   | 
        
           |  |  | 98 |         // Compare Moodle's versions
 | 
        
           |  |  | 99 |         if ($CFG->version < $controller->get_info()->moodle_version) {
 | 
        
           |  |  | 100 |             $message = new stdclass();
 | 
        
           |  |  | 101 |             $message->serverversion = $CFG->version;
 | 
        
           |  |  | 102 |             $message->serverrelease = $CFG->release;
 | 
        
           |  |  | 103 |             $message->backupversion = $controller->get_info()->moodle_version;
 | 
        
           |  |  | 104 |             $message->backuprelease = $controller->get_info()->moodle_release;
 | 
        
           |  |  | 105 |             $warnings[] = get_string('noticenewerbackup','',$message);
 | 
        
           |  |  | 106 |         }
 | 
        
           |  |  | 107 |   | 
        
           |  |  | 108 |         // The original_course_format var was introduced in Moodle 2.9.
 | 
        
           |  |  | 109 |         $originalcourseformat = null;
 | 
        
           |  |  | 110 |         if (!empty($controller->get_info()->original_course_format)) {
 | 
        
           |  |  | 111 |             $originalcourseformat = $controller->get_info()->original_course_format;
 | 
        
           |  |  | 112 |         }
 | 
        
           |  |  | 113 |   | 
        
           |  |  | 114 |         // We can't restore other course's backups on the front page.
 | 
        
           |  |  | 115 |         if ($controller->get_courseid() == SITEID &&
 | 
        
           |  |  | 116 |                 $originalcourseformat != 'site' &&
 | 
        
           |  |  | 117 |                 $controller->get_type() == backup::TYPE_1COURSE) {
 | 
        
           |  |  | 118 |             $errors[] = get_string('errorrestorefrontpagebackup', 'backup');
 | 
        
           |  |  | 119 |         }
 | 
        
           |  |  | 120 |   | 
        
           |  |  | 121 |         // We can't restore front pages over other courses.
 | 
        
           |  |  | 122 |         if ($controller->get_courseid() != SITEID &&
 | 
        
           |  |  | 123 |                 $originalcourseformat == 'site' &&
 | 
        
           |  |  | 124 |                 $controller->get_type() == backup::TYPE_1COURSE) {
 | 
        
           |  |  | 125 |             $errors[] = get_string('errorrestorefrontpagebackup', 'backup');
 | 
        
           |  |  | 126 |         }
 | 
        
           |  |  | 127 |   | 
        
           |  |  | 128 |         // If restoring to different site and restoring users and backup has mnet users warn/error
 | 
        
           |  |  | 129 |         if (!$samesite && $restoreusers && $hasmnetusers) {
 | 
        
           |  |  | 130 |             // User is admin (can create users at sysctx), warn
 | 
        
           |  |  | 131 |             if (has_capability('moodle/user:create', context_system::instance(), $controller->get_userid())) {
 | 
        
           |  |  | 132 |                 $warnings[] = get_string('mnetrestore_extusers_admin', 'admin');
 | 
        
           |  |  | 133 |             // User not admin
 | 
        
           |  |  | 134 |             } else {
 | 
        
           |  |  | 135 |                 $errors[] = get_string('mnetrestore_extusers_noadmin', 'admin');
 | 
        
           |  |  | 136 |             }
 | 
        
           |  |  | 137 |         }
 | 
        
           |  |  | 138 |   | 
        
           |  |  | 139 |         // Load all the inforef files, we are going to need them
 | 
        
           |  |  | 140 |         $progress->start_progress('Loading temporary IDs', count($inforeffiles));
 | 
        
           |  |  | 141 |         $minorstep = 1;
 | 
        
           |  |  | 142 |         foreach ($inforeffiles as $inforeffile) {
 | 
        
           |  |  | 143 |             // Load each inforef file to temp_ids.
 | 
        
           |  |  | 144 |             restore_dbops::load_inforef_to_tempids($restoreid, $inforeffile, $progress);
 | 
        
           |  |  | 145 |             $progress->progress($minorstep++);
 | 
        
           |  |  | 146 |         }
 | 
        
           |  |  | 147 |         $progress->end_progress();
 | 
        
           |  |  | 148 |         $progress->progress($majorstep++);
 | 
        
           |  |  | 149 |   | 
        
           |  |  | 150 |         // If restoring users, check we are able to create all them
 | 
        
           |  |  | 151 |         if ($restoreusers) {
 | 
        
           |  |  | 152 |             $file = $controller->get_plan()->get_basepath() . '/users.xml';
 | 
        
           |  |  | 153 |              // Load needed users to temp_ids.
 | 
        
           |  |  | 154 |             restore_dbops::load_users_to_tempids($restoreid, $file, $progress);
 | 
        
           |  |  | 155 |             $progress->progress($majorstep++);
 | 
        
           |  |  | 156 |             if ($problems = restore_dbops::precheck_included_users($restoreid, $courseid, $userid, $samesite, $progress)) {
 | 
        
           |  |  | 157 |                 $errors = array_merge($errors, $problems);
 | 
        
           |  |  | 158 |             }
 | 
        
           |  |  | 159 |         } else {
 | 
        
           |  |  | 160 |             // To ensure consistent number of steps in progress tracking,
 | 
        
           |  |  | 161 |             // mark progress even though we didn't do anything.
 | 
        
           |  |  | 162 |             $progress->progress($majorstep++);
 | 
        
           |  |  | 163 |         }
 | 
        
           |  |  | 164 |         $progress->progress($majorstep++);
 | 
        
           |  |  | 165 |   | 
        
           |  |  | 166 |         // Note: restore won't create roles at all. Only mapping/skip!
 | 
        
           |  |  | 167 |         $file = $controller->get_plan()->get_basepath() . '/roles.xml';
 | 
        
           |  |  | 168 |         restore_dbops::load_roles_to_tempids($restoreid, $file); // Load needed roles to temp_ids
 | 
        
           |  |  | 169 |         if ($problems = restore_dbops::precheck_included_roles($restoreid, $courseid, $userid, $samesite, $rolemappings)) {
 | 
        
           |  |  | 170 |             $errors = array_key_exists('errors', $problems) ? array_merge($errors, $problems['errors']) : $errors;
 | 
        
           |  |  | 171 |             $warnings = array_key_exists('warnings', $problems) ? array_merge($warnings, $problems['warnings']) : $warnings;
 | 
        
           |  |  | 172 |         }
 | 
        
           |  |  | 173 |         $progress->progress($majorstep++);
 | 
        
           |  |  | 174 |   | 
        
           |  |  | 175 |         // Check we are able to restore and the categories and questions
 | 
        
           |  |  | 176 |         $file = $controller->get_plan()->get_basepath() . '/questions.xml';
 | 
        
           |  |  | 177 |         restore_dbops::load_categories_and_questions_to_tempids($restoreid, $file);
 | 
        
           |  |  | 178 |         if ($problems = restore_dbops::precheck_categories_and_questions($restoreid, $courseid, $userid, $samesite)) {
 | 
        
           |  |  | 179 |             $errors = array_key_exists('errors', $problems) ? array_merge($errors, $problems['errors']) : $errors;
 | 
        
           |  |  | 180 |             $warnings = array_key_exists('warnings', $problems) ? array_merge($warnings, $problems['warnings']) : $warnings;
 | 
        
           |  |  | 181 |         }
 | 
        
           |  |  | 182 |         $progress->progress($majorstep++);
 | 
        
           |  |  | 183 |   | 
        
           |  |  | 184 |         // Prepare results.
 | 
        
           |  |  | 185 |         $results = array();
 | 
        
           |  |  | 186 |         if (!empty($errors)) {
 | 
        
           |  |  | 187 |             $results['errors'] = $errors;
 | 
        
           |  |  | 188 |         }
 | 
        
           |  |  | 189 |         if (!empty($warnings)) {
 | 
        
           |  |  | 190 |             $results['warnings'] = $warnings;
 | 
        
           |  |  | 191 |         }
 | 
        
           |  |  | 192 |         // Warnings/errors detected or want to do so explicitly, drop temp tables
 | 
        
           |  |  | 193 |         if (!empty($results) || $droptemptablesafter) {
 | 
        
           |  |  | 194 |             restore_controller_dbops::drop_restore_temp_tables($controller->get_restoreid());
 | 
        
           |  |  | 195 |         }
 | 
        
           |  |  | 196 |   | 
        
           |  |  | 197 |         // Finish progress and check we got the initial number of steps right.
 | 
        
           |  |  | 198 |         $progress->progress($majorstep++);
 | 
        
           |  |  | 199 |         if ($majorstep != $majorsteps) {
 | 
        
           |  |  | 200 |             throw new coding_exception('Progress step count wrong: ' . $majorstep);
 | 
        
           |  |  | 201 |         }
 | 
        
           |  |  | 202 |         $progress->end_progress();
 | 
        
           |  |  | 203 |   | 
        
           |  |  | 204 |         return $results;
 | 
        
           |  |  | 205 |     }
 | 
        
           |  |  | 206 | }
 | 
        
           |  |  | 207 |   | 
        
           |  |  | 208 | /*
 | 
        
           |  |  | 209 |  * Exception class used by all the @restore_prechecks_helper stuff
 | 
        
           |  |  | 210 |  */
 | 
        
           |  |  | 211 | class restore_prechecks_helper_exception extends backup_exception {
 | 
        
           |  |  | 212 |   | 
        
           |  |  | 213 |     public function __construct($errorcode, $a=NULL, $debuginfo=null) {
 | 
        
           |  |  | 214 |         parent::__construct($errorcode, $a, $debuginfo);
 | 
        
           |  |  | 215 |     }
 | 
        
           |  |  | 216 | }
 |