mirror of
https://github.com/moodle/moodle.git
synced 2025-08-04 08:26:37 +02:00
MDL-22145 backup storage - provide 'user_tohub' storage for HUB files
This commit is contained in:
parent
96449a1698
commit
ce937f9957
11 changed files with 131 additions and 12 deletions
|
@ -98,7 +98,7 @@ abstract class backup implements checksumable {
|
||||||
/*
|
/*
|
||||||
* Exception class used by all the @backup stuff
|
* Exception class used by all the @backup stuff
|
||||||
*/
|
*/
|
||||||
class backup_exception extends moodle_exception {
|
abstract class backup_exception extends moodle_exception {
|
||||||
|
|
||||||
public function __construct($errorcode, $a=NULL, $debuginfo=null) {
|
public function __construct($errorcode, $a=NULL, $debuginfo=null) {
|
||||||
parent::__construct($errorcode, 'error', '', $a, null, $debuginfo);
|
parent::__construct($errorcode, 'error', '', $a, null, $debuginfo);
|
||||||
|
|
|
@ -254,6 +254,10 @@ class backup_controller extends backup implements loggable {
|
||||||
return $this->plan->execute();
|
return $this->plan->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_results() {
|
||||||
|
return $this->plan->get_results();
|
||||||
|
}
|
||||||
|
|
||||||
public function log($message, $level, $a = null, $depth = null, $display = false) {
|
public function log($message, $level, $a = null, $depth = null, $display = false) {
|
||||||
backup_helper::log($message, $level, $a, $depth, $display, $this->logger);
|
backup_helper::log($message, $level, $a, $depth, $display, $this->logger);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,12 @@ class backup_final_task extends backup_task {
|
||||||
// to the backup, settings, license, versions and other useful information
|
// to the backup, settings, license, versions and other useful information
|
||||||
$this->add_step(new backup_main_structure_step('mainfile', 'moodle_backup.xml'));
|
$this->add_step(new backup_main_structure_step('mainfile', 'moodle_backup.xml'));
|
||||||
|
|
||||||
|
// Generate the zip file
|
||||||
|
$this->add_step(new backup_zip_contents('zip_contents'));
|
||||||
|
|
||||||
|
// Copy the generated zip file to final destination
|
||||||
|
$this->add_step(new backup_store_backup_file('save_backupfile'));
|
||||||
|
|
||||||
$this->built = true;
|
$this->built = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1049,6 +1049,59 @@ class backup_main_structure_step extends backup_structure_step {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execution step that will generate the final zip file with all the contents
|
||||||
|
*/
|
||||||
|
class backup_zip_contents extends backup_execution_step {
|
||||||
|
|
||||||
|
protected function define_execution() {
|
||||||
|
|
||||||
|
// Get basepath
|
||||||
|
$basepath = $this->get_basepath();
|
||||||
|
|
||||||
|
// Get the list of files in directory
|
||||||
|
$filestemp = get_directory_list($basepath, '', false, true, true);
|
||||||
|
$files = array();
|
||||||
|
foreach ($filestemp as $file) { // Add zip paths and fs paths to all them
|
||||||
|
$files[$file] = $basepath . '/' . $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the log file if exists
|
||||||
|
$logfilepath = $basepath . '.log';
|
||||||
|
if (file_exists($logfilepath)) {
|
||||||
|
$files['moodle_backup.log'] = $logfilepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the zip fullpath
|
||||||
|
$zipfile = $basepath . '/' . $this->get_setting_value('filename');
|
||||||
|
|
||||||
|
// Get the zip packer
|
||||||
|
$zippacker = get_file_packer('application/zip');
|
||||||
|
|
||||||
|
// Zip files
|
||||||
|
$zippacker->archive_to_pathname($files, $zipfile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This step will send the generated backup file to its final destination
|
||||||
|
*/
|
||||||
|
class backup_store_backup_file extends backup_execution_step {
|
||||||
|
|
||||||
|
protected function define_execution() {
|
||||||
|
|
||||||
|
// Get basepath
|
||||||
|
$basepath = $this->get_basepath();
|
||||||
|
|
||||||
|
// Calculate the zip fullpath
|
||||||
|
$zipfile = $basepath . '/' . $this->get_setting_value('filename');
|
||||||
|
|
||||||
|
// Perform storage and return it (TODO: shouldn't be array but proper result object)
|
||||||
|
return array('backup_destination' => backup_helper::store_backup_file($this->get_backupid(), $zipfile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This step will search for all the activity (not calculations, categories nor aggregations) grade items
|
* This step will search for all the activity (not calculations, categories nor aggregations) grade items
|
||||||
* and put them to the backup_ids tables, to be used later as base to backup them
|
* and put them to the backup_ids tables, to be used later as base to backup them
|
||||||
|
|
|
@ -178,7 +178,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||||
'activity' => $prefix,
|
'activity' => $prefix,
|
||||||
'name' => $setting->get_name(),
|
'name' => $setting->get_name(),
|
||||||
'value' => $setting->get_value());
|
'value' => $setting->get_value());
|
||||||
$settingsinfo[] = (object)$settinginfo;
|
$settingsinfo[$setting->get_name()] = (object)$settinginfo;
|
||||||
}
|
}
|
||||||
return array($contentinfo, $settingsinfo);
|
return array($contentinfo, $settingsinfo);
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||||
'section ' => $prefix,
|
'section ' => $prefix,
|
||||||
'name' => $setting->get_name(),
|
'name' => $setting->get_name(),
|
||||||
'value' => $setting->get_value());
|
'value' => $setting->get_value());
|
||||||
$settingsinfo[] = (object)$settinginfo;
|
$settingsinfo[$setting->get_name()] = (object)$settinginfo;
|
||||||
}
|
}
|
||||||
return array($contentinfo, $settingsinfo);
|
return array($contentinfo, $settingsinfo);
|
||||||
}
|
}
|
||||||
|
@ -245,7 +245,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||||
'level' => 'course',
|
'level' => 'course',
|
||||||
'name' => $setting->get_name(),
|
'name' => $setting->get_name(),
|
||||||
'value' => $setting->get_value());
|
'value' => $setting->get_value());
|
||||||
$settingsinfo[] = (object)$settinginfo;
|
$settingsinfo[$setting->get_name()] = (object)$settinginfo;
|
||||||
}
|
}
|
||||||
return array($contentinfo, $settingsinfo);
|
return array($contentinfo, $settingsinfo);
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||||
'level' => 'root',
|
'level' => 'root',
|
||||||
'name' => $setting->get_name(),
|
'name' => $setting->get_name(),
|
||||||
'value' => $setting->get_value());
|
'value' => $setting->get_value());
|
||||||
$settingsinfo[] = (object)$settinginfo;
|
$settingsinfo[$setting->get_name()] = (object)$settinginfo;
|
||||||
}
|
}
|
||||||
return array(null, $settingsinfo);
|
return array(null, $settingsinfo);
|
||||||
}
|
}
|
||||||
|
@ -291,6 +291,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||||
$detailsinfo['mode'] = $bc->get_mode();
|
$detailsinfo['mode'] = $bc->get_mode();
|
||||||
$detailsinfo['execution'] = $bc->get_execution();
|
$detailsinfo['execution'] = $bc->get_execution();
|
||||||
$detailsinfo['executiontime'] = $bc->get_executiontime();
|
$detailsinfo['executiontime'] = $bc->get_executiontime();
|
||||||
|
$detailsinfo['userid'] = $bc->get_userid();
|
||||||
|
|
||||||
|
|
||||||
// Init content placeholders
|
// Init content placeholders
|
||||||
|
|
|
@ -60,7 +60,7 @@ abstract class backup_factory {
|
||||||
// Create file_logger, observing $CFG->backup_file_logger_level
|
// Create file_logger, observing $CFG->backup_file_logger_level
|
||||||
check_dir_exists($CFG->dataroot . '/temp/backup', true, true); // need to ensure that temp/backup already exists
|
check_dir_exists($CFG->dataroot . '/temp/backup', true, true); // need to ensure that temp/backup already exists
|
||||||
$fllevel = isset($CFG->backup_file_logger_level) ? $CFG->backup_file_logger_level : $dfltloglevel;
|
$fllevel = isset($CFG->backup_file_logger_level) ? $CFG->backup_file_logger_level : $dfltloglevel;
|
||||||
$enabledloggers[] = new file_logger($fllevel, true, true, $CFG->dataroot . '/temp/backup/' . $backupid . '.log.html');
|
$enabledloggers[] = new file_logger($fllevel, true, true, $CFG->dataroot . '/temp/backup/' . $backupid . '.log');
|
||||||
|
|
||||||
// Create database_logger, observing $CFG->backup_database_logger_level and defaulting to LOG_WARNING
|
// Create database_logger, observing $CFG->backup_database_logger_level and defaulting to LOG_WARNING
|
||||||
// and pointing to the backup_logs table
|
// and pointing to the backup_logs table
|
||||||
|
|
|
@ -163,6 +163,44 @@ abstract class backup_helper {
|
||||||
output_controller::get_instance()->output($message, 'backup', $a, $depth);
|
output_controller::get_instance()->output($message, 'backup', $a, $depth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given one backupid and the (FS) final generated file, perform its final storage
|
||||||
|
* into Moodle file storage
|
||||||
|
*/
|
||||||
|
static public function store_backup_file($backupid, $filepath) {
|
||||||
|
|
||||||
|
// First of all, get some information from the backup_controller to help us decide
|
||||||
|
list($dinfo, $cinfo, $sinfo) = backup_controller_dbops::get_moodle_backup_information($backupid);
|
||||||
|
|
||||||
|
// Extract useful information to decide
|
||||||
|
$hasusers = (bool)$sinfo['users']->value; // Backup has users
|
||||||
|
$isannon = (bool)$sinfo['anonymize']->value; // Backup is annonymzed
|
||||||
|
$backupmode= $dinfo[0]->mode; // Backup mode backup::MODE_GENERAL/IMPORT/HUB
|
||||||
|
$userid = $dinfo[0]->userid; // User->id executing the backup
|
||||||
|
|
||||||
|
// Backups of type IMPORT aren't stored ever
|
||||||
|
if ($backupmode == backup::MODE_IMPORT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backups of type HUB (by definition never have user info)
|
||||||
|
// are sent to user's "user_tohub" file area. The upload process
|
||||||
|
// will be responsible for cleaning that filearea once finished
|
||||||
|
if ($backupmode == backup::MODE_HUB) {
|
||||||
|
$ctxid = get_context_instance(CONTEXT_USER, $userid)->id;
|
||||||
|
$fs = get_file_storage();
|
||||||
|
$fr = array(
|
||||||
|
'contextid' => $ctxid,
|
||||||
|
'filearea' => 'user_tohub',
|
||||||
|
'itemid' => 0,
|
||||||
|
'filepath' => '/',
|
||||||
|
'filename' => basename($filepath),
|
||||||
|
'timecreated' => time(),
|
||||||
|
'timemodified'=> time());
|
||||||
|
return $fs->create_file_from_pathname($fr, $filepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -31,7 +31,7 @@ abstract class backup_execution_step extends backup_step {
|
||||||
|
|
||||||
public function execute() {
|
public function execute() {
|
||||||
// Simple, for now
|
// Simple, for now
|
||||||
$this->define_execution();
|
return $this->define_execution();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protected API starts here
|
// Protected API starts here
|
||||||
|
|
|
@ -32,6 +32,7 @@ abstract class base_plan implements checksumable, executable {
|
||||||
protected $name; // One simple name for identification purposes
|
protected $name; // One simple name for identification purposes
|
||||||
protected $settings; // One array of (accumulated from tasks) base_setting elements
|
protected $settings; // One array of (accumulated from tasks) base_setting elements
|
||||||
protected $tasks; // One array of base_task elements
|
protected $tasks; // One array of base_task elements
|
||||||
|
protected $results; // One array of results received from tasks
|
||||||
|
|
||||||
protected $built; // Flag to know if one plan has been built
|
protected $built; // Flag to know if one plan has been built
|
||||||
|
|
||||||
|
@ -42,6 +43,7 @@ abstract class base_plan implements checksumable, executable {
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->settings = array();
|
$this->settings = array();
|
||||||
$this->tasks = array();
|
$this->tasks = array();
|
||||||
|
$this->results = array();
|
||||||
$this->built = false;
|
$this->built = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +70,14 @@ abstract class base_plan implements checksumable, executable {
|
||||||
return $this->tasks;
|
return $this->tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function add_result($result) {
|
||||||
|
$this->results = array_merge($this->results, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_results() {
|
||||||
|
return $this->results;
|
||||||
|
}
|
||||||
|
|
||||||
public function get_settings() {
|
public function get_settings() {
|
||||||
return $this->settings;
|
return $this->settings;
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,12 @@ abstract class base_task implements checksumable, executable, loggable {
|
||||||
throw new base_task_exception('base_task_not_built', $this->name);
|
throw new base_task_exception('base_task_not_built', $this->name);
|
||||||
}
|
}
|
||||||
foreach ($this->steps as $step) {
|
foreach ($this->steps as $step) {
|
||||||
$step->execute();
|
$result = $step->execute();
|
||||||
|
// If step returns array, it will be forwarded to plan
|
||||||
|
// (TODO: shouldn't be array but proper result object)
|
||||||
|
if (is_array($result) and !empty($result)) {
|
||||||
|
$this->plan->add_result($result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,9 +52,10 @@ abstract class base_setting {
|
||||||
const HIDDEN = 0;
|
const HIDDEN = 0;
|
||||||
|
|
||||||
// Editable/locked (by different causes)
|
// Editable/locked (by different causes)
|
||||||
const NOT_LOCKED = 5;
|
const NOT_LOCKED = 3;
|
||||||
const LOCKED_BY_PERMISSION = 6;
|
const LOCKED_BY_CONFIG = 5;
|
||||||
const LOCKED_BY_HIERARCHY = 7;
|
const LOCKED_BY_HIERARCHY = 7;
|
||||||
|
const LOCKED_BY_PERMISSION = 9;
|
||||||
|
|
||||||
// Type of change to inform dependencies
|
// Type of change to inform dependencies
|
||||||
const CHANGED_VALUE = 1;
|
const CHANGED_VALUE = 1;
|
||||||
|
@ -237,8 +238,9 @@ abstract class base_setting {
|
||||||
if (is_null($status)) {
|
if (is_null($status)) {
|
||||||
$status = self::NOT_LOCKED;
|
$status = self::NOT_LOCKED;
|
||||||
}
|
}
|
||||||
if ($status !== self::NOT_LOCKED && $status !== self::LOCKED_BY_PERMISSION && $status !== self::LOCKED_BY_HIERARCHY) {
|
if ($status !== self::NOT_LOCKED && $status !== self::LOCKED_BY_CONFIG &&
|
||||||
throw new base_setting_exception('setting_invalid_status');
|
$status !== self::LOCKED_BY_PERMISSION && $status !== self::LOCKED_BY_HIERARCHY) {
|
||||||
|
throw new base_setting_exception('setting_invalid_status', $status);
|
||||||
}
|
}
|
||||||
return $status;
|
return $status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue