mirror of
https://github.com/moodle/moodle.git
synced 2025-08-09 10:56:56 +02:00
Merge branch 'MDL-42039-master' of git://github.com/sammarshallou/moodle.git
This commit is contained in:
commit
982482f01a
11 changed files with 283 additions and 58 deletions
|
@ -58,6 +58,11 @@ class restore_controller extends base_controller {
|
|||
protected $checksum; // Cache @checksumable results for lighter @is_checksum_correct() uses
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* If you specify a progress monitor, this will be used to report progress
|
||||
* while loading the plan, as well as for future use. (You can change it
|
||||
* for a different one later using set_progress.)
|
||||
*
|
||||
* @param string $tempdir Directory under tempdir/backup awaiting restore
|
||||
* @param int $courseid Course id where restore is going to happen
|
||||
|
@ -65,8 +70,10 @@ class restore_controller extends base_controller {
|
|||
* @param int $mode backup::MODE_[ GENERAL | HUB | IMPORT | SAMESITE ]
|
||||
* @param int $userid
|
||||
* @param int $target backup::TARGET_[ NEW_COURSE | CURRENT_ADDING | CURRENT_DELETING | EXISTING_ADDING | EXISTING_DELETING ]
|
||||
* @param core_backup_progress $progress Optional progress monitor
|
||||
*/
|
||||
public function __construct($tempdir, $courseid, $interactive, $mode, $userid, $target){
|
||||
public function __construct($tempdir, $courseid, $interactive, $mode, $userid, $target,
|
||||
core_backup_progress $progress = null) {
|
||||
$this->tempdir = $tempdir;
|
||||
$this->courseid = $courseid;
|
||||
$this->interactive = $interactive;
|
||||
|
@ -99,9 +106,14 @@ class restore_controller extends base_controller {
|
|||
// Default logger chain (based on interactive/execution)
|
||||
$this->logger = backup_factory::get_logger_chain($this->interactive, $this->execution, $this->restoreid);
|
||||
|
||||
// By default there is no progress reporter. Interfaces that wish to
|
||||
// display progress must set it.
|
||||
$this->progress = new core_backup_null_progress();
|
||||
// By default there is no progress reporter unless you specify one so it
|
||||
// can be used during loading of the plan.
|
||||
if ($progress) {
|
||||
$this->progress = $progress;
|
||||
} else {
|
||||
$this->progress = new core_backup_null_progress();
|
||||
}
|
||||
$this->progress->start_progress('Constructing restore_controller');
|
||||
|
||||
// Instantiate the output_controller singleton and active it if interactive and inmediate
|
||||
$oc = output_controller::get_instance();
|
||||
|
@ -135,6 +147,9 @@ class restore_controller extends base_controller {
|
|||
$this->set_status(backup::STATUS_NEED_PRECHECK);
|
||||
}
|
||||
}
|
||||
|
||||
// Tell progress monitor that we finished loading.
|
||||
$this->progress->end_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,10 +34,13 @@ defined('MOODLE_INTERNAL') || die();
|
|||
class create_and_clean_temp_stuff extends backup_execution_step {
|
||||
|
||||
protected function define_execution() {
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress('Deleting backup directories');
|
||||
backup_helper::check_and_create_backup_dir($this->get_backupid());// Create backup temp dir
|
||||
backup_helper::clear_backup_dir($this->get_backupid()); // Empty temp dir, just in case
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs
|
||||
backup_helper::clear_backup_dir($this->get_backupid(), $progress); // Empty temp dir, just in case
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60), $progress); // Delete > 4 hours temp dirs
|
||||
backup_controller_dbops::create_backup_ids_temp_table($this->get_backupid()); // Create ids temp table
|
||||
$progress->end_progress();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +64,10 @@ class drop_and_clean_temp_stuff extends backup_execution_step {
|
|||
// 1) If $CFG->keeptempdirectoriesonbackup is not enabled
|
||||
// 2) If backup temp dir deletion has been marked to be avoided
|
||||
if (empty($CFG->keeptempdirectoriesonbackup) && !$this->skipcleaningtempdir) {
|
||||
backup_helper::delete_backup_dir($this->get_backupid()); // Empty backup dir
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress('Deleting backup dir');
|
||||
backup_helper::delete_backup_dir($this->get_backupid(), $progress); // Empty backup dir
|
||||
$progress->end_progress();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ abstract class restore_plan_builder {
|
|||
// preloading information to temp table
|
||||
// and other init tasks
|
||||
$plan->add_task(new restore_root_task('root_task'));
|
||||
$controller->get_progress()->progress();
|
||||
|
||||
switch ($controller->get_type()) {
|
||||
case backup::TYPE_1ACTIVITY:
|
||||
|
@ -115,6 +116,7 @@ abstract class restore_plan_builder {
|
|||
// conversion...)
|
||||
// and perform other various final actions.
|
||||
$plan->add_task(new restore_final_task('final_task'));
|
||||
$controller->get_progress()->progress();
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,6 +136,7 @@ abstract class restore_plan_builder {
|
|||
// as far as the module can be missing on restore
|
||||
if ($task = restore_factory::get_restore_activity_task($infoactivity)) { // can be missing
|
||||
$plan->add_task($task);
|
||||
$controller->get_progress()->progress();
|
||||
|
||||
// For the given activity path, add as many block tasks as necessary
|
||||
// TODO: Add blocks, we need to introspect xml here
|
||||
|
@ -141,6 +144,7 @@ abstract class restore_plan_builder {
|
|||
foreach ($blocks as $basepath => $name) {
|
||||
if ($task = restore_factory::get_restore_block_task($name, $basepath)) {
|
||||
$plan->add_task($task);
|
||||
$controller->get_progress()->progress();
|
||||
} else {
|
||||
// TODO: Debug information about block not supported
|
||||
}
|
||||
|
@ -163,6 +167,7 @@ abstract class restore_plan_builder {
|
|||
// Add the section task, responsible for restoring
|
||||
// all the section related information
|
||||
$plan->add_task(restore_factory::get_restore_section_task($infosection));
|
||||
$controller->get_progress()->progress();
|
||||
// For the given section, add as many activity tasks as necessary
|
||||
foreach ($info->activities as $activityid => $activity) {
|
||||
if ($activity->sectionid != $infosection->sectionid) {
|
||||
|
@ -188,6 +193,7 @@ abstract class restore_plan_builder {
|
|||
// all the course related information
|
||||
$task = restore_factory::get_restore_course_task($info->course, $courseid);
|
||||
$plan->add_task($task);
|
||||
$controller->get_progress()->progress();
|
||||
|
||||
// For the given course path, add as many block tasks as necessary
|
||||
// TODO: Add blocks, we need to introspect xml here
|
||||
|
@ -195,6 +201,7 @@ abstract class restore_plan_builder {
|
|||
foreach ($blocks as $basepath => $name) {
|
||||
if ($task = restore_factory::get_restore_block_task($name, $basepath)) {
|
||||
$plan->add_task($task);
|
||||
$controller->get_progress()->progress();
|
||||
} else {
|
||||
// TODO: Debug information about block not supported
|
||||
}
|
||||
|
|
|
@ -65,10 +65,13 @@ class restore_drop_and_clean_temp_stuff extends restore_execution_step {
|
|||
protected function define_execution() {
|
||||
global $CFG;
|
||||
restore_controller_dbops::drop_restore_temp_tables($this->get_restoreid()); // Drop ids temp table
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress('Deleting backup dir');
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60), $progress); // Delete > 4 hours temp dirs
|
||||
if (empty($CFG->keeptempdirectoriesonbackup)) { // Conditionally
|
||||
backup_helper::delete_backup_dir($this->task->get_tempdir()); // Empty restore dir
|
||||
backup_helper::delete_backup_dir($this->task->get_tempdir(), $progress); // Empty restore dir
|
||||
}
|
||||
$progress->end_progress();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,7 +729,8 @@ class restore_create_included_users extends restore_execution_step {
|
|||
|
||||
protected function define_execution() {
|
||||
|
||||
restore_dbops::create_included_users($this->get_basepath(), $this->get_restoreid(), $this->task->get_userid());
|
||||
restore_dbops::create_included_users($this->get_basepath(), $this->get_restoreid(),
|
||||
$this->task->get_userid(), $this->task->get_progress());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3547,6 +3551,10 @@ class restore_create_question_files extends restore_execution_step {
|
|||
protected function define_execution() {
|
||||
global $DB;
|
||||
|
||||
// Track progress, as this task can take a long time.
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress($this->get_name(), core_backup_progress::INDETERMINATE);
|
||||
|
||||
// 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
|
||||
|
@ -3554,6 +3562,9 @@ class restore_create_question_files extends restore_execution_step {
|
|||
WHERE bi.backupid = ?
|
||||
AND bi.itemname = 'question_created'", array($this->get_restoreid()));
|
||||
foreach ($questionsrs as $question) {
|
||||
// Report progress for each question.
|
||||
$progress->progress();
|
||||
|
||||
// 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
|
||||
|
@ -3566,21 +3577,22 @@ class restore_create_question_files extends restore_execution_step {
|
|||
|
||||
// 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);
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
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);
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answer',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true);
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answerfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true);
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'hint',
|
||||
$oldctxid, $this->task->get_userid(), 'question_hint', null, $newctxid, true);
|
||||
$oldctxid, $this->task->get_userid(), 'question_hint', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'correctfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true);
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'partiallycorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true);
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'incorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true);
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
|
||||
// Add qtype dependent files
|
||||
$components = backup_qtype_plugin::get_components_and_fileareas($question->qtype);
|
||||
foreach ($components as $component => $fileareas) {
|
||||
|
@ -3588,11 +3600,12 @@ class restore_create_question_files extends restore_execution_step {
|
|||
// 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);
|
||||
$oldctxid, $this->task->get_userid(), $mapping, $itemid, $newctxid, true, $progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
$questionsrs->close();
|
||||
$progress->end_progress();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,23 @@ $PAGE->set_pagelayout('standard');
|
|||
require_login($course, null, $cm);
|
||||
require_capability('moodle/restore:restorecourse', $context);
|
||||
|
||||
// Show page header.
|
||||
$PAGE->set_title($course->shortname . ': ' . get_string('restore'));
|
||||
$PAGE->set_heading($course->fullname);
|
||||
|
||||
$renderer = $PAGE->get_renderer('core','backup');
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Prepare a progress bar which can display optionally during long-running
|
||||
// operations while setting up the UI.
|
||||
$slowprogress = new core_backup_display_progress_if_slow(get_string('preparingui', 'backup'));
|
||||
|
||||
// Overall, allow 10 units of progress.
|
||||
$slowprogress->start_progress('', 10);
|
||||
|
||||
// This progress section counts for loading the restore controller.
|
||||
$slowprogress->start_progress('', 1, 1);
|
||||
|
||||
// Restore of large courses requires extra memory. Use the amount configured
|
||||
// in admin settings.
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
|
@ -43,15 +60,12 @@ if ($stage & restore_ui::STAGE_CONFIRM + restore_ui::STAGE_DESTINATION) {
|
|||
}
|
||||
}
|
||||
|
||||
$PAGE->set_title($course->shortname . ': ' . get_string('restore'));
|
||||
$PAGE->set_heading($course->fullname);
|
||||
// End progress section for loading restore controller.
|
||||
$slowprogress->end_progress();
|
||||
|
||||
$renderer = $PAGE->get_renderer('core','backup');
|
||||
echo $OUTPUT->header();
|
||||
// This progress section is for the 'process' function below.
|
||||
$slowprogress->start_progress('', 1, 9);
|
||||
|
||||
// Prepare a progress bar which can display optionally during long-running
|
||||
// operations while setting up the UI.
|
||||
$slowprogress = new core_backup_display_progress_if_slow(get_string('preparingui', 'backup'));
|
||||
// Depending on the code branch above, $restore may be a restore_ui or it may
|
||||
// be a restore_ui_independent_stage. Either way, this function exists.
|
||||
$restore->set_progress_reporter($slowprogress);
|
||||
|
@ -62,6 +76,10 @@ if (!$restore->is_independent() && $restore->enforce_changed_dependencies()) {
|
|||
}
|
||||
|
||||
$loghtml = '';
|
||||
// Finish the 'process' progress reporting section, and the overall count.
|
||||
$slowprogress->end_progress();
|
||||
$slowprogress->end_progress();
|
||||
|
||||
if (!$restore->is_independent()) {
|
||||
// Use a temporary (disappearing) progress bar to show the precheck progress if any.
|
||||
$precheckprogress = new core_backup_display_progress_if_slow(get_string('preparingdata', 'backup'));
|
||||
|
|
|
@ -72,10 +72,23 @@ if (!check_dir_exists($tmpdir, true, true)) {
|
|||
// choose the backup file from backup files tree
|
||||
if ($action == 'choosebackupfile') {
|
||||
if ($fileinfo = $browser->get_file_info($filecontext, $component, $filearea, $itemid, $filepath, $filename)) {
|
||||
$filename = restore_controller::get_tempdir_name($course->id, $USER->id);
|
||||
$pathname = $tmpdir . '/' . $filename;
|
||||
$fileinfo->copy_to_pathname($pathname);
|
||||
$restore_url = new moodle_url('/backup/restore.php', array('contextid'=>$contextid, 'filename'=>$filename));
|
||||
if (is_a($fileinfo, 'file_info_stored')) {
|
||||
// Use the contenthash rather than copying the file where possible,
|
||||
// to improve performance and avoid timeouts with large files.
|
||||
$fs = get_file_storage();
|
||||
$params = $fileinfo->get_params();
|
||||
$file = $fs->get_file($params['contextid'], $params['component'], $params['filearea'],
|
||||
$params['itemid'], $params['filepath'], $params['filename']);
|
||||
$restore_url = new moodle_url('/backup/restore.php', array('contextid' => $contextid,
|
||||
'pathnamehash' => $file->get_pathnamehash(), 'contenthash' => $file->get_contenthash()));
|
||||
} else {
|
||||
// If it's some weird other kind of file then use old code.
|
||||
$filename = restore_controller::get_tempdir_name($course->id, $USER->id);
|
||||
$pathname = $tmpdir . '/' . $filename;
|
||||
$fileinfo->copy_to_pathname($pathname);
|
||||
$restore_url = new moodle_url('/backup/restore.php', array(
|
||||
'contextid' => $contextid, 'filename' => $filename));
|
||||
}
|
||||
redirect($restore_url);
|
||||
} else {
|
||||
redirect($url, get_string('filenotfound', 'error'));
|
||||
|
|
|
@ -848,6 +848,9 @@ abstract class restore_dbops {
|
|||
* optionally one source itemname to match itemids
|
||||
* put the corresponding files in the pool
|
||||
*
|
||||
* If you specify a progress reporter, it will get called once per file with
|
||||
* indeterminate progress.
|
||||
*
|
||||
* @param string $basepath the full path to the root of unzipped backup file
|
||||
* @param string $restoreid the restore job's identification
|
||||
* @param string $component
|
||||
|
@ -858,9 +861,13 @@ abstract class restore_dbops {
|
|||
* @param int|null $olditemid
|
||||
* @param int|null $forcenewcontextid explicit value for the new contextid (skip mapping)
|
||||
* @param bool $skipparentitemidctxmatch
|
||||
* @param core_backup_progress $progress Optional progress reporter
|
||||
* @return array of result object
|
||||
*/
|
||||
public static function send_files_to_pool($basepath, $restoreid, $component, $filearea, $oldcontextid, $dfltuserid, $itemname = null, $olditemid = null, $forcenewcontextid = null, $skipparentitemidctxmatch = false) {
|
||||
public static function send_files_to_pool($basepath, $restoreid, $component, $filearea,
|
||||
$oldcontextid, $dfltuserid, $itemname = null, $olditemid = null,
|
||||
$forcenewcontextid = null, $skipparentitemidctxmatch = false,
|
||||
core_backup_progress $progress = null) {
|
||||
global $DB, $CFG;
|
||||
|
||||
$backupinfo = backup_general_helper::get_backup_information(basename($basepath));
|
||||
|
@ -924,8 +931,17 @@ abstract class restore_dbops {
|
|||
|
||||
$fs = get_file_storage(); // Get moodle file storage
|
||||
$basepath = $basepath . '/files/';// Get backup file pool base
|
||||
// Report progress before query.
|
||||
if ($progress) {
|
||||
$progress->progress();
|
||||
}
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $rec) {
|
||||
// Report progress each time around loop.
|
||||
if ($progress) {
|
||||
$progress->progress();
|
||||
}
|
||||
|
||||
$file = (object)backup_controller_dbops::decode_backup_temp_info($rec->info);
|
||||
|
||||
// ignore root dirs (they are created automatically)
|
||||
|
@ -1041,10 +1057,20 @@ abstract class restore_dbops {
|
|||
* in backup_ids having newitemid = 0, as far as
|
||||
* precheck_included_users() have left them there
|
||||
* ready to be created. Also, annotate their newids
|
||||
* once created for later reference
|
||||
* once created for later reference.
|
||||
*
|
||||
* This function will start and end a new progress section in the progress
|
||||
* object.
|
||||
*
|
||||
* @param string $basepath Base path of unzipped backup
|
||||
* @param string $restoreid Restore ID
|
||||
* @param int $userid Default userid for files
|
||||
* @param core_backup_progress $progress Object used for progress tracking
|
||||
*/
|
||||
public static function create_included_users($basepath, $restoreid, $userid) {
|
||||
public static function create_included_users($basepath, $restoreid, $userid,
|
||||
core_backup_progress $progress) {
|
||||
global $CFG, $DB;
|
||||
$progress->start_progress('Creating included users');
|
||||
|
||||
$authcache = array(); // Cache to get some bits from authentication plugins
|
||||
$languages = get_string_manager()->get_list_of_translations(); // Get languages for quick search later
|
||||
|
@ -1053,6 +1079,7 @@ abstract class restore_dbops {
|
|||
// Iterate over all the included users with newitemid = 0, have to create them
|
||||
$rs = $DB->get_recordset('backup_ids_temp', array('backupid' => $restoreid, 'itemname' => 'user', 'newitemid' => 0), '', 'itemid, parentitemid, info');
|
||||
foreach ($rs as $recuser) {
|
||||
$progress->progress();
|
||||
$user = (object)backup_controller_dbops::decode_backup_temp_info($recuser->info);
|
||||
|
||||
// if user lang doesn't exist here, use site default
|
||||
|
@ -1192,11 +1219,14 @@ abstract class restore_dbops {
|
|||
}
|
||||
|
||||
// Create user files in pool (profile, icon, private) by context
|
||||
restore_dbops::send_files_to_pool($basepath, $restoreid, 'user', 'icon', $recuser->parentitemid, $userid);
|
||||
restore_dbops::send_files_to_pool($basepath, $restoreid, 'user', 'profile', $recuser->parentitemid, $userid);
|
||||
restore_dbops::send_files_to_pool($basepath, $restoreid, 'user', 'icon',
|
||||
$recuser->parentitemid, $userid, null, null, null, false, $progress);
|
||||
restore_dbops::send_files_to_pool($basepath, $restoreid, 'user', 'profile',
|
||||
$recuser->parentitemid, $userid, null, null, null, false, $progress);
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
$progress->end_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,10 +41,16 @@ abstract class backup_helper {
|
|||
|
||||
/**
|
||||
* Given one backupid, ensure its temp dir is completely empty
|
||||
*
|
||||
* If supplied, progress object should be ready to receive indeterminate
|
||||
* progress reports.
|
||||
*
|
||||
* @param string $backupid Backup id
|
||||
* @param core_backup_progress $progress Optional progress reporting object
|
||||
*/
|
||||
static public function clear_backup_dir($backupid) {
|
||||
static public function clear_backup_dir($backupid, core_backup_progress $progress = null) {
|
||||
global $CFG;
|
||||
if (!self::delete_dir_contents($CFG->tempdir . '/backup/' . $backupid)) {
|
||||
if (!self::delete_dir_contents($CFG->tempdir . '/backup/' . $backupid, '', $progress)) {
|
||||
throw new backup_helper_exception('cannot_empty_backup_temp_dir');
|
||||
}
|
||||
return true;
|
||||
|
@ -52,10 +58,16 @@ abstract class backup_helper {
|
|||
|
||||
/**
|
||||
* Given one backupid, delete completely its temp dir
|
||||
*
|
||||
* If supplied, progress object should be ready to receive indeterminate
|
||||
* progress reports.
|
||||
*
|
||||
* @param string $backupid Backup id
|
||||
* @param core_backup_progress $progress Optional progress reporting object
|
||||
*/
|
||||
static public function delete_backup_dir($backupid) {
|
||||
static public function delete_backup_dir($backupid, core_backup_progress $progress = null) {
|
||||
global $CFG;
|
||||
self::clear_backup_dir($backupid);
|
||||
self::clear_backup_dir($backupid, $progress);
|
||||
return rmdir($CFG->tempdir . '/backup/' . $backupid);
|
||||
}
|
||||
|
||||
|
@ -63,10 +75,21 @@ abstract class backup_helper {
|
|||
* Given one fullpath to directory, delete its contents recursively
|
||||
* Copied originally from somewhere in the net.
|
||||
* TODO: Modernise this
|
||||
*
|
||||
* If supplied, progress object should be ready to receive indeterminate
|
||||
* progress reports.
|
||||
*
|
||||
* @param string $dir Directory to delete
|
||||
* @param string $excludedir Exclude this directory
|
||||
* @param core_backup_progress $progress Optional progress reporting object
|
||||
*/
|
||||
static public function delete_dir_contents($dir, $excludeddir='') {
|
||||
static public function delete_dir_contents($dir, $excludeddir='', core_backup_progress $progress = null) {
|
||||
global $CFG;
|
||||
|
||||
if ($progress) {
|
||||
$progress->progress();
|
||||
}
|
||||
|
||||
if (!is_dir($dir)) {
|
||||
// if we've been given a directory that doesn't exist yet, return true.
|
||||
// this happens when we're trying to clear out a course that has only just
|
||||
|
@ -108,7 +131,7 @@ abstract class backup_helper {
|
|||
// Empty sub directories and then remove the directory
|
||||
for ($i=0; $i<count($dir_subdirs); $i++) {
|
||||
chmod($dir_subdirs[$i], $CFG->directorypermissions);
|
||||
if (self::delete_dir_contents($dir_subdirs[$i]) == false) {
|
||||
if (self::delete_dir_contents($dir_subdirs[$i], '', $progress) == false) {
|
||||
return false;
|
||||
} else {
|
||||
if (remove_dir($dir_subdirs[$i]) == false) {
|
||||
|
@ -125,9 +148,15 @@ abstract class backup_helper {
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete all the temp dirs older than the time specified
|
||||
* Delete all the temp dirs older than the time specified.
|
||||
*
|
||||
* If supplied, progress object should be ready to receive indeterminate
|
||||
* progress reports.
|
||||
*
|
||||
* @param int $deletefrom Time to delete from
|
||||
* @param core_backup_progress $progress Optional progress reporting object
|
||||
*/
|
||||
static public function delete_old_backup_dirs($deletefrom) {
|
||||
static public function delete_old_backup_dirs($deletefrom, core_backup_progress $progress = null) {
|
||||
global $CFG;
|
||||
|
||||
$status = true;
|
||||
|
@ -140,7 +169,7 @@ abstract class backup_helper {
|
|||
//If directory, recurse
|
||||
if (is_dir($file_path)) {
|
||||
// $file is really the backupid
|
||||
$status = self::delete_backup_dir($file);
|
||||
$status = self::delete_backup_dir($file, $progress);
|
||||
//If file
|
||||
} else {
|
||||
unlink($file_path);
|
||||
|
|
|
@ -108,10 +108,10 @@ abstract class restore_structure_step extends restore_step {
|
|||
|
||||
// And process it, dispatch to target methods in step will start automatically
|
||||
$xmlparser->process();
|
||||
$progress->end_progress();
|
||||
|
||||
// Have finished, launch the after_execute method of all the processing objects
|
||||
$this->launch_after_execute_methods();
|
||||
$progress->end_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,9 +223,20 @@ abstract class restore_structure_step extends restore_step {
|
|||
* 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_backup_progress::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);
|
||||
$filearea, $filesctxid, $this->task->get_userid(), $mappingitemname, $olditemid, null, false,
|
||||
$progress);
|
||||
$resultstoadd = array();
|
||||
foreach ($results as $result) {
|
||||
$this->log($result->message, $result->level);
|
||||
|
|
|
@ -227,6 +227,20 @@ abstract class core_backup_progress {
|
|||
return !empty($this->descriptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks max value of current progress section.
|
||||
*
|
||||
* @return int Current max value (may be core_backup_progress::INDETERMINATE)
|
||||
* @throws coding_exception If not in a progress section
|
||||
*/
|
||||
public function get_current_max() {
|
||||
$max = end($this->maxes);
|
||||
if ($max === false) {
|
||||
throw new coding_exception('Not inside progress section');
|
||||
}
|
||||
return $max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Current progress section description
|
||||
*/
|
||||
|
|
|
@ -185,6 +185,16 @@ class restore_ui_stage_confirm extends restore_ui_independent_stage implements f
|
|||
protected $contextid;
|
||||
protected $filename = null;
|
||||
protected $filepath = null;
|
||||
|
||||
/**
|
||||
* @var string Content hash of archive file to restore (if specified by hash)
|
||||
*/
|
||||
protected $contenthash = null;
|
||||
/**
|
||||
* @var string Pathname hash of stored_file object to restore
|
||||
*/
|
||||
protected $pathnamehash = null;
|
||||
|
||||
protected $details;
|
||||
|
||||
/**
|
||||
|
@ -194,27 +204,54 @@ class restore_ui_stage_confirm extends restore_ui_independent_stage implements f
|
|||
|
||||
public function __construct($contextid) {
|
||||
$this->contextid = $contextid;
|
||||
$this->filename = required_param('filename', PARAM_FILE);
|
||||
$this->filename = optional_param('filename', null, PARAM_FILE);
|
||||
if ($this->filename === null) {
|
||||
// Identify file object by its pathname hash.
|
||||
$this->pathnamehash = required_param('pathnamehash', PARAM_ALPHANUM);
|
||||
|
||||
// The file content hash is also passed for security; users
|
||||
// cannot guess the content hash (unless they know the file contents),
|
||||
// so this guarantees that either the system generated this link or
|
||||
// else the user has access to the restore archive anyhow.
|
||||
$this->contenthash = required_param('contenthash', PARAM_ALPHANUM);
|
||||
}
|
||||
}
|
||||
|
||||
public function process() {
|
||||
global $CFG;
|
||||
if (!file_exists("$CFG->tempdir/backup/".$this->filename)) {
|
||||
throw new restore_ui_exception('invalidrestorefile');
|
||||
}
|
||||
$outcome = $this->extract_file_to_dir();
|
||||
if ($outcome) {
|
||||
fulldelete($this->filename);
|
||||
if ($this->filename) {
|
||||
$archivepath = $CFG->tempdir . '/backup/' . $this->filename;
|
||||
if (!file_exists($archivepath)) {
|
||||
throw new restore_ui_exception('invalidrestorefile');
|
||||
}
|
||||
$outcome = $this->extract_file_to_dir($archivepath);
|
||||
if ($outcome) {
|
||||
fulldelete($archivepath);
|
||||
}
|
||||
} else {
|
||||
$fs = get_file_storage();
|
||||
$storedfile = $fs->get_file_by_hash($this->pathnamehash);
|
||||
if (!$storedfile || $storedfile->get_contenthash() !== $this->contenthash) {
|
||||
throw new restore_ui_exception('invalidrestorefile');
|
||||
}
|
||||
$outcome = $this->extract_file_to_dir($storedfile);
|
||||
}
|
||||
return $outcome;
|
||||
}
|
||||
protected function extract_file_to_dir() {
|
||||
|
||||
/**
|
||||
* Extracts the file.
|
||||
*
|
||||
* @param string|stored_file $source Archive file to extract
|
||||
*/
|
||||
protected function extract_file_to_dir($source) {
|
||||
global $CFG, $USER;
|
||||
|
||||
$this->filepath = restore_controller::get_tempdir_name($this->contextid, $USER->id);
|
||||
|
||||
$fb = get_file_packer('application/vnd.moodle.backup');
|
||||
$result = $fb->extract_to_pathname("$CFG->tempdir/backup/".$this->filename,
|
||||
"$CFG->tempdir/backup/$this->filepath/", null, $this);
|
||||
$result = $fb->extract_to_pathname($source,
|
||||
$CFG->tempdir . '/backup/' . $this->filepath . '/', null, $this);
|
||||
|
||||
// If any progress happened, end it.
|
||||
if ($this->startedprogress) {
|
||||
|
@ -486,6 +523,11 @@ class restore_ui_stage_settings extends restore_ui_stage {
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class restore_ui_stage_schema extends restore_ui_stage {
|
||||
/**
|
||||
* @var int Maximum number of settings to add to form at once
|
||||
*/
|
||||
const MAX_SETTINGS_BATCH = 1000;
|
||||
|
||||
/**
|
||||
* Schema stage constructor
|
||||
* @param backup_moodleform $ui
|
||||
|
@ -550,6 +592,12 @@ class restore_ui_stage_schema extends restore_ui_stage {
|
|||
$tasks = $this->ui->get_tasks();
|
||||
$courseheading = false;
|
||||
|
||||
// Track progress through each stage.
|
||||
$progress = $this->ui->get_progress_reporter();
|
||||
$progress->start_progress('Initialise schema stage form', 3);
|
||||
|
||||
$progress->start_progress('', count($tasks));
|
||||
$done = 1;
|
||||
$allsettings = array();
|
||||
foreach ($tasks as $task) {
|
||||
if (!($task instanceof restore_root_task)) {
|
||||
|
@ -576,16 +624,37 @@ class restore_ui_stage_schema extends restore_ui_stage {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Update progress.
|
||||
$progress->progress($done++);
|
||||
}
|
||||
$progress->end_progress();
|
||||
|
||||
// Actually add all the settings that we put in the array.
|
||||
$form->add_settings($allsettings);
|
||||
// Add settings for tasks in batches of up to 1000. Adding settings
|
||||
// in larger batches improves performance, but if it takes too long,
|
||||
// we won't be able to update the progress bar so the backup might
|
||||
// time out. 1000 is chosen to balance this.
|
||||
$numsettings = count($allsettings);
|
||||
$progress->start_progress('', ceil($numsettings / self::MAX_SETTINGS_BATCH));
|
||||
$start = 0;
|
||||
$done = 1;
|
||||
while($start < $numsettings) {
|
||||
$length = min(self::MAX_SETTINGS_BATCH, $numsettings - $start);
|
||||
$form->add_settings(array_slice($allsettings, $start, $length));
|
||||
$start += $length;
|
||||
$progress->progress($done++);
|
||||
}
|
||||
$progress->end_progress();
|
||||
|
||||
// Add the dependencies for all the settings.
|
||||
$progress->start_progress('', count($allsettings));
|
||||
$done = 1;
|
||||
foreach ($allsettings as $settingtask) {
|
||||
$form->add_dependencies($settingtask[0]);
|
||||
$progress->progress($done++);
|
||||
}
|
||||
$progress->end_progress();
|
||||
|
||||
$progress->end_progress();
|
||||
$this->stageform = $form;
|
||||
}
|
||||
return $this->stageform;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue