Differences Between: [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Helper functions for asynchronous backups and restores. 19 * 20 * @package core 21 * @copyright 2019 Matt Porritt <mattp@catalyst-au.net> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 require_once($CFG->dirroot . '/user/lib.php'); 28 29 /** 30 * Helper functions for asynchronous backups and restores. 31 * 32 * @package core 33 * @copyright 2019 Matt Porritt <mattp@catalyst-au.net> 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 */ 36 class async_helper { 37 38 /** 39 * @var string $type The type of async operation. 40 */ 41 protected $type = 'backup'; 42 43 /** 44 * @var string $backupid The id of the backup or restore. 45 */ 46 protected $backupid; 47 48 /** 49 * @var object $user The user who created the backup record. 50 */ 51 protected $user; 52 53 /** 54 * @var object $backuprec The backup controller record from the database. 55 */ 56 protected $backuprec; 57 58 /** 59 * Class constructor. 60 * 61 * @param string $type The type of async operation. 62 * @param string $id The id of the backup or restore. 63 */ 64 public function __construct($type, $id) { 65 $this->type = $type; 66 $this->backupid = $id; 67 $this->backuprec = self::get_backup_record($id); 68 $this->user = $this->get_user(); 69 } 70 71 /** 72 * Given a backup id return a the record from the database. 73 * We use this method rather than 'load_controller' as the controller may 74 * not exist if this backup/restore has completed. 75 * 76 * @param int $id The backup id to get. 77 * @return object $backuprec The backup controller record. 78 */ 79 static public function get_backup_record($id) { 80 global $DB; 81 82 $backuprec = $DB->get_record('backup_controllers', array('backupid' => $id), '*', MUST_EXIST); 83 84 return $backuprec; 85 } 86 87 /** 88 * Given a user id return a user object. 89 * 90 * @return object $user The limited user record. 91 */ 92 private function get_user() { 93 $userid = $this->backuprec->userid; 94 $user = core_user::get_user($userid, '*', MUST_EXIST); 95 96 return $user; 97 } 98 99 /** 100 * Callback for preg_replace_callback. 101 * Replaces message placeholders with real values. 102 * 103 * @param array $matches The match array from from preg_replace_callback. 104 * @return string $match The replaced string. 105 */ 106 private function lookup_message_variables($matches) { 107 $options = array( 108 'operation' => $this->type, 109 'backupid' => $this->backupid, 110 'user_username' => $this->user->username, 111 'user_email' => $this->user->email, 112 'user_firstname' => $this->user->firstname, 113 'user_lastname' => $this->user->lastname, 114 'link' => $this->get_resource_link(), 115 ); 116 117 $match = $options[$matches[1]] ?? $matches[1]; 118 119 return $match; 120 } 121 122 /** 123 * Get the link to the resource that is being backuped or restored. 124 * 125 * @return moodle_url $url The link to the resource. 126 */ 127 private function get_resource_link() { 128 // Get activity context only for backups. 129 if ($this->backuprec->type == 'activity' && $this->type == 'backup') { 130 $context = context_module::instance($this->backuprec->itemid); 131 } else { // Course or Section which have the same context getter. 132 $context = context_course::instance($this->backuprec->itemid); 133 } 134 135 // Generate link based on operation type. 136 if ($this->type == 'backup') { 137 // For backups simply generate link to restore file area UI. 138 $url = new moodle_url('/backup/restorefile.php', array('contextid' => $context->id)); 139 } else { 140 // For restore generate link to the item itself. 141 $url = $context->get_url(); 142 } 143 144 return $url; 145 } 146 147 /** 148 * Sends a confirmation message for an aynchronous process. 149 * 150 * @return int $messageid The id of the sent message. 151 */ 152 public function send_message() { 153 global $USER; 154 155 $subjectraw = get_config('backup', 'backup_async_message_subject'); 156 $subjecttext = preg_replace_callback( 157 '/\{([-_A-Za-z0-9]+)\}/u', 158 array('async_helper', 'lookup_message_variables'), 159 $subjectraw); 160 161 $messageraw = get_config('backup', 'backup_async_message'); 162 $messagehtml = preg_replace_callback( 163 '/\{([-_A-Za-z0-9]+)\}/u', 164 array('async_helper', 'lookup_message_variables'), 165 $messageraw); 166 $messagetext = html_to_text($messagehtml); 167 168 $message = new \core\message\message(); 169 $message->component = 'moodle'; 170 $message->name = 'asyncbackupnotification'; 171 $message->userfrom = $USER; 172 $message->userto = $this->user; 173 $message->subject = $subjecttext; 174 $message->fullmessage = $messagetext; 175 $message->fullmessageformat = FORMAT_HTML; 176 $message->fullmessagehtml = $messagehtml; 177 $message->smallmessage = ''; 178 $message->notification = '1'; 179 180 $messageid = message_send($message); 181 182 return $messageid; 183 } 184 185 /** 186 * Check if asynchronous backup and restore mode is 187 * enabled at system level. 188 * 189 * @return bool $async True if async mode enabled false otherwise. 190 */ 191 static public function is_async_enabled() { 192 global $CFG; 193 194 $async = false; 195 if (!empty($CFG->enableasyncbackup)) { 196 $async = true; 197 } 198 199 return $async; 200 } 201 202 /** 203 * Check if there is a pending async operation for given details. 204 * 205 * @param int $id The item id to check in the backup record. 206 * @param string $type The type of operation: course, activity or section. 207 * @param string $operation Operation backup or restore. 208 * @return boolean $asyncpedning Is there a pending async operation. 209 */ 210 public static function is_async_pending($id, $type, $operation) { 211 global $DB, $USER, $CFG; 212 $asyncpending = false; 213 214 // Only check for pending async operations if async mode is enabled. 215 require_once($CFG->dirroot . '/backup/util/interfaces/checksumable.class.php'); 216 require_once($CFG->dirroot . '/backup/backup.class.php'); 217 218 $select = 'userid = ? AND itemid = ? AND type = ? AND operation = ? AND execution = ? AND status < ? AND status > ?'; 219 $params = array( 220 $USER->id, 221 $id, 222 $type, 223 $operation, 224 backup::EXECUTION_DELAYED, 225 backup::STATUS_FINISHED_ERR, 226 backup::STATUS_NEED_PRECHECK 227 ); 228 229 $asyncrecord= $DB->get_record_select('backup_controllers', $select, $params); 230 231 if ((self::is_async_enabled() && $asyncrecord) || ($asyncrecord && $asyncrecord->purpose == backup::MODE_COPY)) { 232 $asyncpending = true; 233 } 234 return $asyncpending; 235 } 236 237 /** 238 * Get the size, url and restore url for a backup file. 239 * 240 * @param string $filename The name of the file to get info for. 241 * @param string $filearea The file area for the file. 242 * @param int $contextid The context ID of the file. 243 * @return array $results The result array containing the size, url and restore url of the file. 244 */ 245 public static function get_backup_file_info($filename, $filearea, $contextid) { 246 $fs = get_file_storage(); 247 $file = $fs->get_file($contextid, 'backup', $filearea, 0, '/', $filename); 248 $filesize = display_size ($file->get_filesize()); 249 $fileurl = moodle_url::make_pluginfile_url( 250 $file->get_contextid(), 251 $file->get_component(), 252 $file->get_filearea(), 253 null, 254 $file->get_filepath(), 255 $file->get_filename(), 256 true 257 ); 258 259 $params = array(); 260 $params['action'] = 'choosebackupfile'; 261 $params['filename'] = $file->get_filename(); 262 $params['filepath'] = $file->get_filepath(); 263 $params['component'] = $file->get_component(); 264 $params['filearea'] = $file->get_filearea(); 265 $params['filecontextid'] = $file->get_contextid(); 266 $params['contextid'] = $contextid; 267 $params['itemid'] = $file->get_itemid(); 268 $restoreurl = new moodle_url('/backup/restorefile.php', $params); 269 $filesize = display_size ($file->get_filesize()); 270 271 $results = array( 272 'filesize' => $filesize, 273 'fileurl' => $fileurl->out(false), 274 'restoreurl' => $restoreurl->out(false)); 275 276 return $results; 277 } 278 279 /** 280 * Get the url of a restored backup item based on the backup ID. 281 * 282 * @param string $backupid The backup ID to get the restore location url. 283 * @return array $urlarray The restored item URL as an array. 284 */ 285 public static function get_restore_url($backupid) { 286 global $DB; 287 288 $backupitemid = $DB->get_field('backup_controllers', 'itemid', array('backupid' => $backupid), MUST_EXIST); 289 $newcontext = context_course::instance($backupitemid); 290 291 $restoreurl = $newcontext->get_url()->out(); 292 $urlarray = array('restoreurl' => $restoreurl); 293 294 return $urlarray; 295 } 296 297 /** 298 * Get markup for in progress async backups, 299 * to use in backup table UI. 300 * 301 * @param \core_backup_renderer $renderer The backup renderer object. 302 * @param integer $instanceid The context id to get backup data for. 303 * @return array $tabledata the rows of table data. 304 */ 305 public static function get_async_backups($renderer, $instanceid) { 306 global $DB; 307 308 $tabledata = array(); 309 310 // Get relevant backup ids based on context instance id. 311 $select = 'itemid = :itemid AND execution = :execution AND status < :status1 AND status > :status2 ' . 312 'AND operation = :operation'; 313 $params = [ 314 'itemid' => $instanceid, 315 'execution' => backup::EXECUTION_DELAYED, 316 'status1' => backup::STATUS_FINISHED_ERR, 317 'status2' => backup::STATUS_NEED_PRECHECK, 318 'operation' => 'backup', 319 ]; 320 321 $backups = $DB->get_records_select('backup_controllers', $select, $params, 'timecreated DESC', 'id, backupid, timecreated'); 322 foreach ($backups as $backup) { 323 $bc = \backup_controller::load_controller($backup->backupid); // Get the backup controller. 324 $filename = $bc->get_plan()->get_setting('filename')->get_value(); 325 $timecreated = $backup->timecreated; 326 $status = $renderer->get_status_display($bc->get_status(), $bc->get_backupid()); 327 $bc->destroy(); 328 329 $tablerow = array($filename, userdate($timecreated), '-', '-', '-', $status); 330 $tabledata[] = $tablerow; 331 } 332 333 return $tabledata; 334 } 335 336 /** 337 * Get the course name of the resource being restored. 338 * 339 * @param \context $context The Moodle context for the restores. 340 * @return string $coursename The full name of the course. 341 */ 342 public static function get_restore_name(\context $context) { 343 global $DB; 344 $instanceid = $context->instanceid; 345 346 if ($context->contextlevel == CONTEXT_MODULE) { 347 // For modules get the course name and module name. 348 $cm = get_coursemodule_from_id('', $context->instanceid, 0, false, MUST_EXIST); 349 $coursename = $DB->get_field('course', 'fullname', array('id' => $cm->course)); 350 $itemname = $coursename . ' - ' . $cm->name; 351 } else { 352 $itemname = $DB->get_field('course', 'fullname', array('id' => $context->instanceid)); 353 354 } 355 356 return $itemname; 357 } 358 359 /** 360 * Get all the current in progress async restores for a user. 361 * 362 * @param int $userid Moodle user id. 363 * @return array $restores List of current restores in progress. 364 */ 365 public static function get_async_restores($userid) { 366 global $DB; 367 368 $select = 'userid = ? AND execution = ? AND status < ? AND status > ? AND operation = ?'; 369 $params = array($userid, backup::EXECUTION_DELAYED, backup::STATUS_FINISHED_ERR, backup::STATUS_NEED_PRECHECK, 'restore'); 370 $restores = $DB->get_records_select( 371 'backup_controllers', 372 $select, 373 $params, 374 'timecreated DESC', 375 'id, backupid, status, itemid, timecreated'); 376 377 return $restores; 378 } 379 380 } 381
title
Description
Body
title
Description
Body
title
Description
Body
title
Body