MDL-21432 backup - now restoring ras/caps and "manual" enrolment plugins.
authorEloy Lafuente <stronk7@moodle.org>
Wed, 21 Jul 2010 19:30:15 +0000 (19:30 +0000)
committerEloy Lafuente <stronk7@moodle.org>
Wed, 21 Jul 2010 19:30:15 +0000 (19:30 +0000)
TODO: Complete the enrolments part and fix current implementation, it's only one skeleton

backup/moodle2/restore_course_task.class.php
backup/moodle2/restore_stepslib.php
backup/util/dbops/restore_dbops.class.php
backup/util/helper/restore_roles_parser_processor.class.php
backup/util/helper/restore_users_parser_processor.class.php

index eccc25f..ec2e74a 100644 (file)
@@ -31,6 +31,7 @@
 class restore_course_task extends restore_task {
 
     protected $info; // info related to course gathered from backup file
+    protected $contextid; // course context id
 
     /**
      * Constructor - instantiates one object of this class
@@ -48,17 +49,29 @@ class restore_course_task extends restore_task {
         return $this->get_basepath() . '/course';
     }
 
+    public function get_contextid() {
+        return $this->contextid;
+    }
+
     /**
      * Create all the steps that will be part of this task
      */
     public function build() {
 
-        // TODO: Link all the course steps here
+        // Define the task contextid (the course one)
+        $this->contextid = get_context_instance(CONTEXT_COURSE, $this->get_courseid())->id;
+
         // Executed conditionally if restoring to new course or deleting or if overwrite_conf setting is enabled
         if ($this->get_target() == backup::TARGET_NEW_COURSE || $this->get_setting_value('overwrite_conf') == true) {
             $this->add_step(new restore_course_structure_step('course_info', 'course.xml'));
         }
 
+        // Restore course role assignments and overrides (internally will observe the role_assignments setting)
+        $this->add_step(new restore_ras_and_caps_structure_step('course_ras_and_caps', 'roles.xml'));
+
+        // Restore course enrolments (plugins and membership)
+        $this->add_step(new restore_enrolments_structure_step('course_enrolments', 'enrolments.xml'));
+
         // At the end, mark it as built
         $this->built = true;
     }
index 47c52c7..9b8c306 100644 (file)
@@ -558,3 +558,139 @@ class restore_course_structure_step extends restore_structure_step {
         $this->add_related_files('course', 'legacy', null);
     }
 }
+
+
+/*
+ * Structure step that will read the roles.xml file (at course/activity/block levels)
+ * containig all the role_assignments and overrides for that context. If corresponding to
+ * one mapped role, they will be applied to target context. Will observe the role_assignments
+ * setting to decide if ras are restored.
+ * Note: only ras with component == null are restored as far as the any ra with component
+ * is handled by one enrolment plugin, hence it will createt the ras later
+ */
+class restore_ras_and_caps_structure_step extends restore_structure_step {
+
+    protected function define_structure() {
+
+        $paths = array();
+
+        // Observe the role_assignments setting
+        if ($this->get_setting_value('role_assignments')) {
+            $paths[] = new restore_path_element('assignment', '/roles/role_assignments/assignment');
+        }
+        $paths[] = new restore_path_element('override', '/roles/role_overrides/override');
+
+        return $paths;
+    }
+
+    public function process_assignment($data) {
+        $data = (object)$data;
+
+        // Check roleid, userid are one of the mapped ones
+        $newroleid = $this->get_mappingid('role', $data->roleid);
+        $newuserid = $this->get_mappingid('user', $data->userid);
+        // If newroleid and newuserid and component is empty assign via API (handles dupes and friends)
+        if ($newroleid && $newuserid && empty($data->component)) {
+            // TODO: role_assign() needs one userid param to be able to specify our restore userid
+            role_assign($newroleid, $newuserid, $this->task->get_contextid());
+        }
+    }
+
+    public function process_override($data) {
+        $data = (object)$data;
+
+        // Check roleid is one of the mapped ones
+        $newroleid = $this->get_mappingid('role', $data->roleid);
+        // If newroleid is valid assign it via API (it handles dupes and so on)
+        if ($newroleid) {
+            // TODO: assign_capability() needs one userid param to be able to specify our restore userid
+            assign_capability($data->capability, $data->permission, $newroleid, $this->task->get_contextid());
+        }
+    }
+}
+
+/**
+ * This structure steps restores the enrol plugins and their underlying
+ * enrolments, performing all the mappings and/or movements required
+ */
+class restore_enrolments_structure_step extends restore_structure_step {
+
+    protected function define_structure() {
+
+        $paths = array();
+
+        $paths[] = new restore_path_element('enrol', '/enrolments/enrols/enrol');
+        $paths[] = new restore_path_element('enrolment', '/enrolments/enrols/enrol/user_enrolments/enrolment');
+
+        return $paths;
+    }
+
+    public function process_enrol($data) {
+        global $DB;
+
+        $data = (object)$data;
+        $oldid = $data->id; // We'll need this later
+
+        // TODO: Just one quick process of manual enrol_plugin. Add the rest (complex ones) and fix this
+        if ($data->enrol !== 'manual') {
+            debugging("Skipping '{$data->enrol}' enrolment plugin. Must be implemented", DEBUG_DEVELOPER);
+            return;
+        }
+
+        // Perform various checks to decide what to do with the enrol plugin
+        $installed = array_key_exists($data->enrol, enrol_get_plugins(false));
+        $enabled   = enrol_is_enabled($data->enrol);
+        $exists    = 0;
+        $roleid    = $this->get_mappingid('role', $data->roleid);
+        if ($rec = $DB->get_record('enrol', array('courseid' => $this->get_courseid(), 'enrol' => $data->enrol))) {
+            $exists = $rec->id;
+        }
+        // If installed and enabled, continue processing
+        if ($installed && $enabled) {
+            // If not exists in course and we have a target role mapping
+            if (!$exists && $roleid) {
+                $data->roleid = $roleid;
+                $enrol = enrol_get_plugin($data->enrol);
+                $courserec = $DB->get_record('course', array('id' => $this->get_courseid())); // Requires object, uses only id!!
+                $newitemid = $enrol->add_instance($courserec, array($data));
+
+            // Already exists, user it for enrolments
+            } else {
+                $newitemid = $exists;
+            }
+
+        // Not installed and enabled, map to 0
+        } else {
+            $newitemid = 0;
+        }
+        // Perform the simple mapping and done
+        $this->set_mapping('enrol', $oldid, $newitemid);
+    }
+
+    public function process_enrolment($data) {
+        global $DB;
+
+        $data = (object)$data;
+
+        // Process only if parent instance have been mapped
+        if ($enrolid = $this->get_new_parentid('enrol')) {
+            // And only if user is a mapped one
+            if ($userid = $this->get_mappingid('user', $data->userid)) {
+                // TODO: Surely need to use API (enrol_user) here, instead of the current low-level impl
+                // TODO: Note enrol_user() sticks to $USER->id (need to add userid param)
+                $enrolment = new stdclass();
+                $enrolment->enrolid = $enrolid;
+                $enrolment->userid  = $userid;
+                if (!$DB->record_exists('user_enrolments', (array)$enrolment)) {
+                    $enrolment->status = $data->status;
+                    $enrolment->timestart = $data->timestart;
+                    $enrolment->timeend = $data->timeend;
+                    $enrolment->modifierid = $this->task->get_userid();
+                    $enrolment->timecreated = time();
+                    $enrolment->timemodified = 0;
+                    $DB->insert_record('user_enrolments', $enrolment);
+                }
+            }
+        }
+    }
+}
index fae07e4..cc67e2d 100644 (file)
@@ -873,8 +873,8 @@ abstract class restore_dbops {
         foreach ($rs as $recrole) {
             // Get the complete temp_ids record
             $role = (object)self::get_backup_ids_record($restoreid, 'role', $recrole->itemid);
-            // If it's one mapped role
-            if (!empty($role->newitemid)) {
+            // If it's one mapped role and we have one name for it
+            if (!empty($role->newitemid) && !empty($role->info['nameincourse'])) {
                 // If role name doesn't exist, add it
                 $rolename = new stdclass();
                 $rolename->roleid = $role->newitemid;
index f051af9..2729ae0 100644 (file)
@@ -54,4 +54,14 @@ class restore_roles_parser_processor extends grouped_parser_processor {
             restore_dbops::set_backup_ids_record($this->restoreid, $itemname, $itemid, 0, null, $info);
         }
     }
+
+    /**
+     * Provide NULL decoding
+     */
+    public function process_cdata($cdata) {
+        if ($cdata === '$@NULL@$') {
+            return null;
+        }
+        return $cdata;
+    }
 }
index 709dcd3..c999ad0 100644 (file)
@@ -65,4 +65,14 @@ class restore_users_parser_processor extends grouped_parser_processor {
             restore_dbops::set_backup_ids_record($this->restoreid, $itemname, $itemid, 0, $parentitemid, $info);
         }
     }
+
+    /**
+     * Provide NULL decoding
+     */
+    public function process_cdata($cdata) {
+        if ($cdata === '$@NULL@$') {
+            return null;
+        }
+        return $cdata;
+    }
 }