MDL-22145 backup storage - provide 'user_tohub' storage for HUB files
authorEloy Lafuente <stronk7@moodle.org>
Tue, 27 Apr 2010 01:02:38 +0000 (01:02 +0000)
committerEloy Lafuente <stronk7@moodle.org>
Tue, 27 Apr 2010 01:02:38 +0000 (01:02 +0000)
backup/backup.class.php
backup/controller/backup_controller.class.php
backup/moodle2/backup_final_task.class.php
backup/moodle2/backup_stepslib.php
backup/util/dbops/backup_controller_dbops.class.php
backup/util/factories/backup_factory.class.php
backup/util/helper/backup_helper.class.php
backup/util/plan/backup_execution_step.class.php
backup/util/plan/base_plan.class.php
backup/util/plan/base_task.class.php
backup/util/settings/base_setting.class.php

index 2f932d3..1cc1684 100644 (file)
@@ -98,7 +98,7 @@ abstract class backup implements checksumable {
 /*
  * 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) {
         parent::__construct($errorcode, 'error', '', $a, null, $debuginfo);
index c3580ca..ddb857f 100644 (file)
@@ -254,6 +254,10 @@ class backup_controller extends backup implements loggable {
         return $this->plan->execute();
     }
 
+    public function get_results() {
+        return $this->plan->get_results();
+    }
+
     public function log($message, $level, $a = null, $depth = null, $display = false) {
         backup_helper::log($message, $level, $a, $depth, $display, $this->logger);
     }
index b28860a..52778ad 100644 (file)
@@ -84,6 +84,12 @@ class backup_final_task extends backup_task {
         // to the backup, settings, license, versions and other useful information
         $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;
     }
 
index 75937b9..bc34174 100644 (file)
@@ -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
  * and put them to the backup_ids tables, to be used later as base to backup them
index 7ceabbe..01d12d9 100644 (file)
@@ -178,7 +178,7 @@ abstract class backup_controller_dbops extends backup_dbops {
                 'activity' => $prefix,
                 'name'     => $setting->get_name(),
                 'value'    => $setting->get_value());
-            $settingsinfo[] = (object)$settinginfo;
+            $settingsinfo[$setting->get_name()] = (object)$settinginfo;
         }
         return array($contentinfo, $settingsinfo);
     }
@@ -212,7 +212,7 @@ abstract class backup_controller_dbops extends backup_dbops {
                 'section ' => $prefix,
                 'name'     => $setting->get_name(),
                 'value'    => $setting->get_value());
-            $settingsinfo[] = (object)$settinginfo;
+            $settingsinfo[$setting->get_name()] = (object)$settinginfo;
         }
         return array($contentinfo, $settingsinfo);
     }
@@ -245,7 +245,7 @@ abstract class backup_controller_dbops extends backup_dbops {
                 'level'    => 'course',
                 'name'     => $setting->get_name(),
                 'value'    => $setting->get_value());
-            $settingsinfo[] = (object)$settinginfo;
+            $settingsinfo[$setting->get_name()] = (object)$settinginfo;
         }
         return array($contentinfo, $settingsinfo);
     }
@@ -267,7 +267,7 @@ abstract class backup_controller_dbops extends backup_dbops {
                 'level'    => 'root',
                 'name'     => $setting->get_name(),
                 'value'    => $setting->get_value());
-            $settingsinfo[] = (object)$settinginfo;
+            $settingsinfo[$setting->get_name()] = (object)$settinginfo;
         }
         return array(null, $settingsinfo);
     }
@@ -291,6 +291,7 @@ abstract class backup_controller_dbops extends backup_dbops {
         $detailsinfo['mode'] = $bc->get_mode();
         $detailsinfo['execution'] = $bc->get_execution();
         $detailsinfo['executiontime'] = $bc->get_executiontime();
+        $detailsinfo['userid'] = $bc->get_userid();
 
 
         // Init content placeholders
index fe15e0d..7e334b8 100644 (file)
@@ -60,7 +60,7 @@ abstract class backup_factory {
         // 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
         $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
         // and pointing to the backup_logs table
index d770c06..782fa66 100644 (file)
@@ -163,6 +163,44 @@ abstract class backup_helper {
             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);
+        }
+    }
 }
 
 /*
index 20a4450..178a9d9 100644 (file)
@@ -31,7 +31,7 @@ abstract class backup_execution_step extends backup_step {
 
     public function execute() {
         // Simple, for now
-        $this->define_execution();
+        return $this->define_execution();
     }
 
 // Protected API starts here
index fa2f767..97e8e38 100644 (file)
@@ -32,6 +32,7 @@ abstract class base_plan implements checksumable, executable {
     protected $name;      // One simple name for identification purposes
     protected $settings;  // One array of (accumulated from tasks) base_setting 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
 
@@ -42,6 +43,7 @@ abstract class base_plan implements checksumable, executable {
         $this->name = $name;
         $this->settings = array();
         $this->tasks    = array();
+        $this->results  = array();
         $this->built = false;
     }
 
@@ -68,6 +70,14 @@ abstract class base_plan implements checksumable, executable {
         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() {
         return $this->settings;
     }
index 0aafe72..1ac7014 100644 (file)
@@ -144,7 +144,12 @@ abstract class base_task implements checksumable, executable, loggable {
             throw new base_task_exception('base_task_not_built', $this->name);
         }
         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);
+            }
         }
     }
 
index ae06436..41f1c62 100644 (file)
@@ -52,9 +52,10 @@ abstract class base_setting {
     const HIDDEN  = 0;
 
     // Editable/locked (by different causes)
-    const NOT_LOCKED           = 5;
-    const LOCKED_BY_PERMISSION = 6;
+    const NOT_LOCKED           = 3;
+    const LOCKED_BY_CONFIG     = 5;
     const LOCKED_BY_HIERARCHY  = 7;
+    const LOCKED_BY_PERMISSION = 9;
 
     // Type of change to inform dependencies
     const CHANGED_VALUE      = 1;
@@ -237,8 +238,9 @@ abstract class base_setting {
         if (is_null($status)) {
             $status = self::NOT_LOCKED;
         }
-        if ($status !== self::NOT_LOCKED && $status !== self::LOCKED_BY_PERMISSION && $status !== self::LOCKED_BY_HIERARCHY) {
-            throw new base_setting_exception('setting_invalid_status');
+        if ($status !== self::NOT_LOCKED && $status !== self::LOCKED_BY_CONFIG &&
+            $status !== self::LOCKED_BY_PERMISSION && $status !== self::LOCKED_BY_HIERARCHY) {
+            throw new base_setting_exception('setting_invalid_status', $status);
         }
         return $status;
     }