course-import MDL-23752 Implemented course import functionality back into Moodle 2.0
authorSam Hemelryk <sam@moodle.com>
Tue, 17 Aug 2010 02:07:30 +0000 (02:07 +0000)
committerSam Hemelryk <sam@moodle.com>
Tue, 17 Aug 2010 02:07:30 +0000 (02:07 +0000)
The course import now makes use of the backup and restore processed and the backup UI to allow the user to import one course into another.
The new UI is much the same as the backup ui except preceeded by a course selector to choose the course to import from.

backup/import.php [new file with mode: 0644]
backup/restore.php
backup/util/ui/backup_ui.class.php
backup/util/ui/base_moodleform.class.php
backup/util/ui/import_extensions.php [new file with mode: 0644]
backup/util/ui/renderer.php
lang/en/backup.php
lib/navigationlib.php

diff --git a/backup/import.php b/backup/import.php
new file mode 100644 (file)
index 0000000..35e7784
--- /dev/null
@@ -0,0 +1,159 @@
+<?php
+
+// Require both the backup and restore libs
+require_once('../config.php');
+require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
+require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
+require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
+require_once($CFG->dirroot . '/backup/util/ui/import_extensions.php');
+
+// The courseid we are importing to
+$courseid = required_param('id', PARAM_INT);
+// The id of the course we are importing FROM (will only be set if past first stage
+$importcourseid = optional_param('importid', false, PARAM_INT);
+// The target method for the restore (adding or deleting)
+$restoretarget = optional_param('target', backup::TARGET_CURRENT_ADDING, PARAM_INT);
+
+// Load the course and context
+$course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
+$context = get_context_instance(CONTEXT_COURSE, $courseid);
+
+// Must pass login
+require_login($course);
+// Must hold restoretargetimport in the current course
+require_capability('moodle/restore:restoretargetimport', $context);
+
+$heading = get_string('import');
+
+// Set up the page
+$PAGE->set_title($heading);
+$PAGE->set_heading($heading);
+$PAGE->set_url(new moodle_url('/backup/import.php', array('id'=>$courseid)));
+$PAGE->set_context($context);
+$PAGE->set_pagelayout('incourse');
+
+// Prepare the backup renderer
+$renderer = $PAGE->get_renderer('core','backup');
+
+// Check if we already have a import course id
+if ($importcourseid === false) {
+    // Obviously not... show the selector so one can be chosen
+    $url = new moodle_url('/backup/import.php', array('id'=>$courseid));
+    $search = new import_course_search(array('url'=>$url));
+
+    // show the course selector
+    echo $OUTPUT->header();
+    echo $renderer->import_course_selector($url, $search);
+    echo $OUTPUT->footer();
+    die();
+}
+
+// Load the course +context to import from
+$importcourse = $DB->get_record('course', array('id'=>$importcourseid), '*', MUST_EXIST);
+$importcontext = get_context_instance(CONTEXT_COURSE, $importcourseid);
+
+// Make sure the user can backup from that course
+require_capability('moodle/backup:backuptargetimport', $importcontext);
+
+// Attempt to load the existing backup controller (backupid will be false if there isn't one)
+$backupid = optional_param('backup', false, PARAM_ALPHANUM);
+if (!($bc = backup_ui::load_controller($backupid))) {
+    $bc = new backup_controller(backup::TYPE_1COURSE, $importcourse->id, backup::FORMAT_MOODLE,
+                            backup::INTERACTIVE_YES, backup::MODE_GENERAL, $USER->id);
+    $bc->get_plan()->get_setting('users')->set_status(backup_setting::LOCKED_BY_CONFIG);
+    $settings = $bc->get_plan()->get_settings();
+
+    // For the initial stage we want to hide all locked settings and if there are
+    // no visible settings move to the next stage
+    $visiblesettings = false;
+    foreach ($settings as $setting) {
+        if ($setting->get_status() !== backup_setting::NOT_LOCKED) {
+            $setting->set_visibility(backup_setting::HIDDEN);
+        } else {
+            $visiblesettings = true;
+        }
+    }
+    import_ui::skip_current_stage(!$visiblesettings);
+}
+
+// Prepare the import UI
+$backup = new import_ui($bc, array('importid'=>$importcourse->id, 'target'=>$restoretarget));
+// Process the current stage
+$backup->process();
+
+// If this is the confirmation stage remove the filename setting
+if ($backup->get_stage() == backup_ui::STAGE_CONFIRMATION) {
+    $backup->get_setting('filename')->set_visibility(backup_setting::HIDDEN);
+}
+
+// If it's the final stage process the import
+if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
+    // First execute the backup
+    $backup->execute();
+
+    // Check whether the backup directory still exists and if it doesn't extract the
+    // backup file so that we have it
+    $tempdestination = $CFG->dataroot . '/temp/backup/' . $backupid;
+    if (!file_exists($tempdestination) || !is_dir($tempdestination)) {
+        $results = $backup->get_controller()->get_results();
+        $file = $results['backup_destination'];
+        $file->extract_to_pathname(get_file_packer($file->get_mimetype()), $tempdestination);
+    }
+    // Delete the backup file, we only want the directory
+    $results['backup_destination']->delete();
+
+    // Prepare the restore controller. We don't need a UI here as we will just use what
+    // ever the restore has (the user has just chosen).
+    $rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_YES, backup::MODE_GENERAL, $USER->id, $restoretarget);
+    // Convert the backup if required.... it should NEVER happed
+    if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) {
+        $rc->convert();
+    }
+    // Mark the UI finished.
+    $rc->finish_ui();
+    // Execute prechecks
+    if (!$rc->execute_precheck()) {
+        $precheckresults = $rc->get_precheck_results();
+        if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
+            fulldelete($tempdestination);
+
+            echo $OUTPUT->header();
+            echo $renderer->precheck_notices($precheckresults);
+            echo $OUTPUT->continue_button(new moodle_url('/course/view.php', array('id'=>$course->id)));
+            echo $OUTPUT->footer();
+            die();
+        }
+    } else {
+        // Execute the restore
+        $rc->execute_plan();
+    }
+
+    // Delete the temp directory now
+    fulldelete($tempdestination);
+
+    // Display a notification and a continue button
+    echo $OUTPUT->header();
+    echo $OUTPUT->notification(get_string('importsuccess', 'backup'),'notifysuccess');
+    echo $OUTPUT->continue_button(new moodle_url('/course/view.php', array('id'=>$course->id)));
+    echo $OUTPUT->footer();
+
+    die();
+
+} else {
+    // Otherwise save the controller and progress
+    $backup->save_controller();
+}
+
+// Adjust the page for the stage
+$PAGE->set_title($heading.': '.$backup->get_stage_name());
+$PAGE->set_heading($heading.': '.$backup->get_stage_name());
+$PAGE->navbar->add($backup->get_stage_name());
+
+// Display the current stage
+echo $OUTPUT->header();
+if ($backup->enforce_changed_dependencies()) {
+    echo $renderer->dependency_notification(get_string('dependenciesenforced','backup'));
+}
+echo $renderer->progress_bar($backup->get_progress_bar());
+echo $backup->display();
+echo $OUTPUT->footer();
\ No newline at end of file
index 313e6b2..084ab1f 100644 (file)
@@ -17,8 +17,6 @@ $PAGE->set_pagelayout('standard');
 require_login($course, null, $cm);
 require_capability('moodle/restore:restorecourse', $context);
 
-$isfrontpage = ($course->id == SITEID);
-
 if ($stage & restore_ui::STAGE_CONFIRM + restore_ui::STAGE_DESTINATION) {
     $restore = restore_ui::engage_independent_stage($stage, $contextid);
 } else {
index 01435df..70c7166 100644 (file)
@@ -42,6 +42,12 @@ class backup_ui extends base_ui {
     const STAGE_FINAL = 8;
     const STAGE_COMPLETE = 16;
 
+    /**
+     * If set to true the current stage is skipped.
+     * @var bool
+     */
+    protected static $skipcurrentstage = false;
+
     /**
      * Intialises what ever stage is requested. If none are requested we check
      * params for 'stage' and default to initial
@@ -53,6 +59,9 @@ class backup_ui extends base_ui {
         if ($stage == null) {
             $stage = optional_param('stage', self::STAGE_INITIAL, PARAM_INT);
         }
+        if (self::$skipcurrentstage) {
+            $stage *= 2;
+        }
         switch ($stage) {
             case backup_ui::STAGE_INITIAL:
                 $stage = new backup_ui_stage_initial($this, $params);
@@ -72,6 +81,10 @@ class backup_ui extends base_ui {
         }
         return $stage;
     }
+    /**
+     * Returns the backup id
+     * @return string
+     */
     public function get_uniqueid() {
         return $this->get_backupid();
     }
@@ -150,22 +163,40 @@ class backup_ui extends base_ui {
                 $classes[] = 'backup_stage_complete';
             }
             $item = array('text' => strlen(decbin($stage)).'. '.get_string('currentstage'.$stage, 'backup'),'class' => join(' ', $classes));
-            if ($stage < $currentstage && $currentstage < self::STAGE_COMPLETE) {
-                $item['link'] = new moodle_url($PAGE->url, array('backup'=>$this->get_backupid(), 'stage'=>$stage));
+            if ($stage < $currentstage && $currentstage < self::STAGE_COMPLETE && (!self::$skipcurrentstage || ($stage*2) != $currentstage)) {
+                $params = $this->stage->get_params();
+                if (empty($params)) {
+                    $params = array();
+                }
+                $params = array_merge($params, array('backup'=>$this->get_backupid(), 'stage'=>$stage));
+                $item['link'] = new moodle_url($PAGE->url, $params);
             }
             array_unshift($items, $item);
             $stage = floor($stage/2);
         }
         return $items;
     }
-
+    /**
+     * Gets the name related to the operation of this UI
+     * @return string
+     */
     public function get_name() {
         return 'backup';
     }
-
+    /**
+     * Gets the id of the first stage this UI is reponsible for
+     * @return int
+     */
     public function get_first_stage_id() {
         return self::STAGE_INITIAL;
     }
+    /**
+     * If called with default arg the current stage gets skipped.
+     * @static
+     */
+    public static function skip_current_stage($setting=true) {
+        self::$skipcurrentstage = $setting;
+    }
 }
 
 /**
index d483f48..3b88377 100644 (file)
@@ -257,4 +257,49 @@ abstract class base_moodleform extends moodleform {
     public function is_cancelled() {
         return (optional_param('cancel', false, PARAM_BOOL) || parent::is_cancelled());
     }
+
+    /**
+     * Removes an element from the form if it exists
+     * @param string $elementName
+     * @return bool
+     */
+    public function remove_element($elementName) {
+        if ($this->_form->elementExists($elementname)) {
+            return $this->_form->removeElement($elementName);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Gets an element from the form if it exists
+     *
+     * @param string $elementname
+     * @return HTML_QuickForm_input|MoodleQuickForm_group
+     */
+    public function get_element($elementname) {
+        if ($this->_form->elementExists($elementname)) {
+            return $this->_form->getElement($elementname);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Displays the form
+     */
+    public function display() {
+        $this->require_definition_after_data();
+        parent::display();
+    }
+
+    /**
+     * Ensures the the definition after data is loaded
+     */
+    public function require_definition_after_data() {
+        if (!$this->_definition_finalized) {
+            $this->_definition_finalized = true;
+            $this->definition_after_data();
+        }
+    }
 }
\ No newline at end of file
diff --git a/backup/util/ui/import_extensions.php b/backup/util/ui/import_extensions.php
new file mode 100644 (file)
index 0000000..b4f9068
--- /dev/null
@@ -0,0 +1,161 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains extension of the backup classes that override some methods
+ * and functionality in order to customise the backup UI for the purposes of
+ * import.
+ *
+ * @package   moodlecore
+ * @copyright 2010 Sam Hemelryk
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Import UI class
+ */
+class import_ui extends backup_ui {
+    /**
+     * Customises the backup progress bar
+     *
+     * @global moodle_page $PAGE
+     * @return array
+     */
+    public function get_progress_bar() {
+        global $PAGE;
+        $stage = self::STAGE_COMPLETE;
+        $currentstage = $this->stage->get_stage();
+        $items = array();
+        while ($stage > 0) {
+            $classes = array('backup_stage');
+            if (floor($stage/2) == $currentstage) {
+                $classes[] = 'backup_stage_next';
+            } else if ($stage == $currentstage) {
+                $classes[] = 'backup_stage_current';
+            } else if ($stage < $currentstage) {
+                $classes[] = 'backup_stage_complete';
+            }
+            $item = array('text' => strlen(decbin($stage*2)).'. '.get_string('importcurrentstage'.$stage, 'backup'),'class' => join(' ', $classes));
+            if ($stage < $currentstage && $currentstage < self::STAGE_COMPLETE && (!self::$skipcurrentstage || $stage*2 != $currentstage)) {
+                $item['link'] = new moodle_url($PAGE->url, $this->stage->get_params() + array('backup'=>$this->get_backupid(), 'stage'=>$stage));
+            }
+            array_unshift($items, $item);
+            $stage = floor($stage/2);
+        }
+        $selectorlink = new moodle_url($PAGE->url, $this->stage->get_params());
+        $selectorlink->remove_params('importid');
+        array_unshift($items, array(
+                'text' => '1. '.get_string('importcurrentstage0', 'backup'),
+                'class' => join(' ', $classes),
+                'link' => $selectorlink));
+        return $items;
+    }
+
+    /**
+     * Intialises what ever stage is requested. If none are requested we check
+     * params for 'stage' and default to initial
+     *
+     * @param int|null $stage The desired stage to intialise or null for the default
+     * @return backup_ui_stage_initial|backup_ui_stage_schema|backup_ui_stage_confirmation|backup_ui_stage_final
+     */
+    protected function initialise_stage($stage = null, array $params=null) {
+        if ($stage == null) {
+            $stage = optional_param('stage', self::STAGE_INITIAL, PARAM_INT);
+        }
+        if (self::$skipcurrentstage) {
+            $stage *= 2;
+        }
+        switch ($stage) {
+            case backup_ui::STAGE_INITIAL:
+                $stage = new import_ui_stage_inital($this, $params);
+                break;
+            case backup_ui::STAGE_SCHEMA:
+                $stage = new import_ui_stage_schema($this, $params);
+                break;
+            case backup_ui::STAGE_CONFIRMATION:
+                $stage = new import_ui_stage_confirmation($this, $params);
+                break;
+            case backup_ui::STAGE_FINAL:
+                $stage = new import_ui_stage_final($this, $params);
+                break;
+            default:
+                $stage = false;
+                break;
+        }
+        return $stage;
+    }
+}
+
+/**
+ * Extends the initial stage
+ */
+class import_ui_stage_inital extends backup_ui_stage_initial {}
+
+/**
+ * Extends the schema stage
+ */
+class import_ui_stage_schema extends backup_ui_stage_schema {}
+
+/**
+ * Extends the confirmation stage.
+ *
+ * This overides the initialise stage form to remove the filenamesetting heading
+ * as it is always hidden.
+ */
+class import_ui_stage_confirmation extends backup_ui_stage_confirmation {
+
+    /**
+     * Initialises the stages moodleform
+     * @return moodleform
+     */
+    protected function initialise_stage_form() {
+        $form = parent::initialise_stage_form();
+        $form->remove_element('filenamesetting');
+        return $form;
+    }
+
+    /**
+     * Displays the stage
+     *
+     * This function is overriden so that we can manipulate the strings on the
+     * buttons.
+     */
+    public function display() {
+        $form = $this->initialise_stage_form();
+        $form->require_definition_after_data();
+        if ($e = $form->get_element('submitbutton')) {
+            $e->setLabel(get_string('import'.$this->get_ui()->get_name().'stage'.$this->get_stage().'action', 'backup'));
+        } else {
+            $elements = $form->get_element('buttonar')->getElements();
+            foreach ($elements as &$element) {
+                if ($element->getName()=='submitbutton') {
+                    $element->setValue(get_string('import'.$this->get_ui()->get_name().'stage'.$this->get_stage().'action', 'backup'));
+                }
+            }
+        }
+        $form->display();
+    }
+}
+/**
+ * Overrides the final stage.
+ */
+class import_ui_stage_final extends backup_ui_stage_final {}
+
+/**
+ * Extends the restore course search to search for import courses.
+ */
+class import_course_search extends restore_course_search {}
\ No newline at end of file
index 65a8950..47995eb 100644 (file)
@@ -64,6 +64,13 @@ class core_backup_renderer extends plugin_renderer_base {
         return html_writer::tag('div', $message, array('class'=>'notification dependencies_enforced'));
     }
 
+    /**
+     * Displays the details of a backup file
+     *
+     * @param stdClass $details
+     * @param moodle_url $nextstageurl
+     * @return string
+     */
     public function backup_details($details, $nextstageurl) {
         $yestick = $this->output->pix_icon('i/tick_green_big', get_string('yes'));
         $notick = $this->output->pix_icon('i/cross_red_big', get_string('no'));
@@ -146,7 +153,17 @@ class core_backup_renderer extends plugin_renderer_base {
         return $html;
     }
 
-    public function course_selector(moodle_url $nextstageurl, $details, $categories, restore_course_search $courses=null, $currentcourse = null) {
+    /**
+     * Displays a course selector for restore
+     *
+     * @param moodle_url $nextstageurl
+     * @param stdClass $details
+     * @param restore_category_search $categories
+     * @param restore_course_search $courses
+     * @param int $currentcourse
+     * @return string
+     */
+    public function course_selector(moodle_url $nextstageurl, $details, restore_category_search $categories = null, restore_course_search $courses=null, $currentcourse = null) {
         global $CFG;
         require_once($CFG->dirroot.'/course/lib.php');
 
@@ -172,7 +189,7 @@ class core_backup_renderer extends plugin_renderer_base {
             $html .= html_writer::end_tag('form');
         }
 
-        if ($categories->get_resultscount() > 0 || $categories->get_search() == '') {
+        if (!empty($categories) && ($categories->get_resultscount() > 0 || $categories->get_search() == '')) {
             // New course
             $html .= $form;
             $html .= html_writer::start_tag('div', array('class'=>'bcs-new-course backup-section'));
@@ -185,7 +202,7 @@ class core_backup_renderer extends plugin_renderer_base {
             $html .= html_writer::end_tag('form');
         }
 
-        if ($courses->get_resultscount() > 0 || $courses->get_search() == '') {
+        if (!empty($courses) && ($courses->get_resultscount() > 0 || $courses->get_search() == '')) {
             // Existing course
             $html .= $form;
             $html .= html_writer::start_tag('div', array('class'=>'bcs-existing-course backup-section'));
@@ -202,6 +219,39 @@ class core_backup_renderer extends plugin_renderer_base {
         return $html;
     }
 
+    /**
+     * Displays the import course selector
+     *
+     * @param moodle_url $nextstageurl
+     * @param import_course_search $courses
+     * @return string
+     */
+    public function import_course_selector(moodle_url $nextstageurl, import_course_search $courses=null) {
+        $html  = html_writer::start_tag('div', array('class'=>'import-course-selector backup-restore'));
+        $html .= html_writer::start_tag('form', array('method'=>'post', 'action'=>$nextstageurl->out_omit_querystring()));
+        foreach ($nextstageurl->params() as $key=>$value) {
+            $html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$key, 'value'=>$value));
+        }
+        $html .= html_writer::start_tag('div', array('class'=>'ics-existing-course backup-section'));
+        $html .= $this->output->heading(get_string('importdatafrom'), 2, array('class'=>'header'));
+        $html .= $this->backup_detail_input(get_string('importadding', 'backup'), 'radio', 'target', backup::TARGET_CURRENT_ADDING, array('checked'=>'checked'), get_string('importaddingdesc', 'backup'));
+        $html .= $this->backup_detail_input(get_string('importdeleting', 'backup'), 'radio', 'target', backup::TARGET_CURRENT_DELETING, array(), get_string('importdeletingdesc', 'backup'));
+        $html .= $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses));
+        $html .= $this->backup_detail_pair('', html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('continue'))));
+        $html .= html_writer::end_tag('div');
+        $html .= html_writer::end_tag('form');
+        $html .= html_writer::end_tag('div');
+        return $html;
+    }
+
+    /**
+     * Creates a detailed pairing (key + value)
+     *
+     * @staticvar int $count
+     * @param string $label
+     * @param string $value
+     * @return string
+     */
     protected function backup_detail_pair($label, $value) {
         static $count= 0;
         $count++;
@@ -212,6 +262,17 @@ class core_backup_renderer extends plugin_renderer_base {
         return $html;
     }
 
+    /**
+     * Created a detailed pairing with an input
+     *
+     * @param string $label
+     * @param string $type
+     * @param string $name
+     * @param string $value
+     * @param array $attributes
+     * @param string|null $description
+     * @return string
+     */
     protected function backup_detail_input($label, $type, $name, $value, array $attributes=array(), $description=null) {
         if (!empty ($description)) {
             $description = html_writer::tag('span', $description, array('class'=>'description'));
@@ -221,6 +282,18 @@ class core_backup_renderer extends plugin_renderer_base {
         return $this->backup_detail_pair($label, html_writer::empty_tag('input', $attributes+array('name'=>$name, 'type'=>$type, 'value'=>$value)).$description);
     }
 
+    /**
+     * Creates a detailed pairing with a select
+     *
+     * @param string $label
+     * @param string $name
+     * @param array $options
+     * @param string $selected
+     * @param bool $nothing
+     * @param array $attributes
+     * @param string|null $description
+     * @return string
+     */
     protected function backup_detail_select($label, $name, $options, $selected='', $nothing=false, array $attributes=array(), $description=null) {
         if (!empty ($description)) {
             $description = html_writer::tag('span', $description, array('class'=>'description'));
@@ -230,6 +303,12 @@ class core_backup_renderer extends plugin_renderer_base {
         return $this->backup_detail_pair($label, html_writer::select($options, $name, $selected, false, $attributes).$description);
     }
 
+    /**
+     * Displays precheck notices
+     *
+     * @param array $results
+     * @return string
+     */
     public function precheck_notices($results) {
         $output = html_writer::start_tag('div', array('class'=>'restore-precheck-notices'));
         if (array_key_exists('errors', $results)) {
@@ -245,6 +324,12 @@ class core_backup_renderer extends plugin_renderer_base {
         return $output.html_writer::end_tag('div');
     }
 
+    /**
+     * Displays substage buttons
+     *
+     * @param bool $haserrors
+     * @return string
+     */
     public function substage_buttons($haserrors) {
         $output  = html_writer::start_tag('div', array('continuebutton'));
         if (!$haserrors) {
@@ -255,6 +340,13 @@ class core_backup_renderer extends plugin_renderer_base {
         return $output;
     }
 
+    /**
+     * Displays a role mapping interface
+     *
+     * @param array $rolemappings
+     * @param array $roles
+     * @return string
+     */
     public function role_mappings($rolemappings, $roles) {
         $roles[0] = get_string('none');
         $output  = html_writer::start_tag('div', array('class'=>'restore-rolemappings'));
@@ -269,6 +361,13 @@ class core_backup_renderer extends plugin_renderer_base {
         return $output;
     }
 
+    /**
+     * Displays a continue button
+     *
+     * @param string|moodle_url $url
+     * @param string $method
+     * @return string
+     */
     public function continue_button($url, $method='post') {
         if (!($url instanceof moodle_url)) {
             $url = new moodle_url($url);
@@ -291,6 +390,13 @@ class core_backup_renderer extends plugin_renderer_base {
         return $this->render($tree);
     }
 
+    /**
+     * Displays a backup files viewer
+     *
+     * @global stdClass $USER
+     * @param backup_files_viewer $tree
+     * @return string
+     */
     public function render_backup_files_viewer(backup_files_viewer $tree) {
         global $USER;
         $user_context = get_context_instance(CONTEXT_USER, $USER->id);
@@ -337,6 +443,12 @@ class core_backup_renderer extends plugin_renderer_base {
         return $html;
     }
 
+    /**
+     * Renders a restore course search object
+     *
+     * @param restore_course_search $component
+     * @return string
+     */
     public function render_restore_course_search(restore_course_search $component) {
         $url = $component->get_url();
 
@@ -386,6 +498,67 @@ class core_backup_renderer extends plugin_renderer_base {
         return $output;
     }
 
+    /**
+     * Renders an import course search object
+     *
+     * @param import_course_search $component
+     * @return string
+     */
+    public function render_import_course_search(import_course_search $component) {
+        $url = $component->get_url();
+
+        $output = html_writer::start_tag('div', array('class' => 'import-course-search'));
+        if ($component->get_totalcount() === 0) {
+            $output .= $this->output->notification(get_string('nomatchingcourses', 'backup'));
+            $output .= html_writer::end_tag('div');
+            return $output;
+        }
+
+        $output .= html_writer::tag('div', get_string('totalcoursesearchresults', 'backup', $component->get_totalcount()), array('class'=>'ics-totalresults'));
+
+        $output .= html_writer::start_tag('div', array('class' => 'ics-results'));
+        if ($component->get_totalpages()>1) {
+            $pagingbar = new paging_bar($component->get_totalcount(), $component->get_page(), $component->get_pagelimit(), new moodle_url($url, array('searchcourses'=>1)), restore_course_search::$VAR_PAGE);
+            $output .= $this->output->render($pagingbar);
+        }
+
+        $table = new html_table();
+        $table->head = array('', get_string('shortname'), get_string('fullname'));
+        $table->data = array();
+        foreach ($component->get_results() as $course) {
+            $row = new html_table_row();
+            $row->attributes['class'] = 'ics-course';
+            if (!$course->visible) {
+                $row->attributes['class'] .= ' dimmed';
+            }
+            $row->cells = array(
+                html_writer::empty_tag('input', array('type'=>'radio', 'name'=>'importid', 'value'=>$course->id)),
+                $course->shortname,
+                $course->fullname
+            );
+            $table->data[] = $row;
+        }
+        $output .= html_writer::table($table);
+        if (isset($pagingbar)) {
+            $output .= $this->output->render($pagingbar);
+        }
+        $output .= html_writer::end_tag('div');
+
+        $output .= html_writer::start_tag('div', array('class'=>'ics-search'));
+        $output .= html_writer::empty_tag('input', array('type'=>'text', 'name'=>restore_course_search::$VAR_SEARCH, 'value'=>$component->get_search()));
+        $output .= html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'searchcourses', 'value'=>get_string('search')));
+        $output .= html_writer::end_tag('div');
+
+        $output .= html_writer::end_tag('div');
+        return $output;
+    }
+
+    /**
+     * Renders a restore category search object
+     * 
+     * @param restore_category_search $component
+     * @return string
+     */
     public function render_restore_category_search(restore_category_search $component) {
         $url = $component->get_url();
 
index 73d9209..08f7f3f 100644 (file)
@@ -88,6 +88,22 @@ $string['generaluserscompletion'] = 'Include user completion information';
 $string['generaluserfiles'] = 'Include user files';
 $string['generalusers'] = 'Include users';
 $string['importfile'] = 'Import a backup file';
+$string['importadding'] = 'Import adding';
+$string['importaddingdesc'] = 'Merge the selected course into this course';
+$string['importbackupstage1action'] = 'Next';
+$string['importbackupstage2action'] = 'Next';
+$string['importbackupstage4action'] = 'Perform import';
+$string['importbackupstage8action'] = 'Continue';
+$string['importbackupstage16action'] = 'Continue';
+$string['importcurrentstage0'] = 'Course selection';
+$string['importcurrentstage1'] = 'Initial settings';
+$string['importcurrentstage2'] = 'Schema settings';
+$string['importcurrentstage4'] = 'Confirmation and review';
+$string['importcurrentstage8'] = 'Perform import';
+$string['importcurrentstage16'] = 'Complete';
+$string['importdeleting'] = 'Import deleting';
+$string['importdeletingdesc'] = 'Delete the contents of this course and then import the selected course';
+$string['importsuccess'] = 'Import complete. Click continue to return to the course.';
 $string['includeactivities'] = 'Choose activities to include';
 $string['includesection'] = 'Include section {$a}';
 $string['includeuserinfo'] = 'Include user information';
index 9877811..d09f7a0 100644 (file)
@@ -1516,13 +1516,15 @@ class global_navigation extends navigation_node {
             if (!$issitecourse) {
                 // Not the current user so add it to the participants node for the current course
                 $usersnode = $coursenode->get('participants', navigation_node::TYPE_CONTAINER);
+                $userviewurl = new moodle_url('/user/view.php', $baseargs);
             } else {
                 // This is the site so add a users node to the root branch
                 $usersnode = $this->rootnodes['users'];
                 $usersnode->action = new moodle_url('/user/index.php', array('id'=>$course->id));
+                $userviewurl = new moodle_url('/user/profile.php', $baseargs);
             }
             // Add a branch for the current user
-            $usernode = $usersnode->add(fullname($user, true), null, self::TYPE_USER, null, $user->id);
+            $usernode = $usersnode->add(fullname($user, true), $userviewurl, self::TYPE_USER, null, $user->id);
 
             if ($this->page->context->contextlevel == CONTEXT_USER && $user->id == $this->page->context->instanceid) {
                 $usernode->make_active();
@@ -2855,8 +2857,7 @@ class settings_navigation extends navigation_node {
 
         // Import data from other courses
         if (has_capability('moodle/restore:restoretargetimport', $coursecontext)) {
-            $url = new moodle_url('/course/import.php', array('id'=>$course->id));
-            $url = null; // Disabled until restore is implemented. MDL-21432
+            $url = new moodle_url('/backup/import.php', array('id'=>$course->id));
             $coursenode->add(get_string('import'), $url, self::TYPE_SETTING, null, 'import', new pix_icon('i/restore', ''));
         }