Merge branch 'MDL-66709' of https://github.com/timhunt/moodle
This commit is contained in:
@@ -55,6 +55,7 @@ class backup_controller extends base_controller {
|
||||
|
||||
protected $status; // Current status of the controller (created, planned, configured...)
|
||||
|
||||
/** @var backup_plan */
|
||||
protected $plan; // Backup execution plan
|
||||
protected $includefiles; // Whether this backup includes files or not.
|
||||
|
||||
|
||||
@@ -34,13 +34,27 @@ defined('MOODLE_INTERNAL') || die();
|
||||
*/
|
||||
abstract class backup_plugin {
|
||||
|
||||
/** @var string */
|
||||
protected $plugintype;
|
||||
/** @var string */
|
||||
protected $pluginname;
|
||||
/** @var string */
|
||||
protected $connectionpoint;
|
||||
/** @var backup_optigroup_element */
|
||||
protected $optigroup; // Optigroup, parent of all optigroup elements
|
||||
/** @var backup_structure_step */
|
||||
protected $step;
|
||||
/** @var backup_course_task|backup_activity_task */
|
||||
protected $task;
|
||||
|
||||
/**
|
||||
* backup_plugin constructor.
|
||||
*
|
||||
* @param string $plugintype
|
||||
* @param string $pluginname
|
||||
* @param backup_optigroup_element $optigroup
|
||||
* @param backup_structure_step $step
|
||||
*/
|
||||
public function __construct($plugintype, $pluginname, $optigroup, $step) {
|
||||
$this->plugintype = $plugintype;
|
||||
$this->pluginname = $pluginname;
|
||||
|
||||
@@ -125,10 +125,9 @@ abstract class backup_activity_structure_step extends backup_structure_step {
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract structure step, to be used by all the activities using core questions stuff
|
||||
* (namely quiz module), supporting question plugins, states and sessions
|
||||
* Helper code for use by any plugin that stores question attempt data that it needs to back up.
|
||||
*/
|
||||
abstract class backup_questions_activity_structure_step extends backup_activity_structure_step {
|
||||
trait backup_questions_attempt_data_trait {
|
||||
|
||||
/**
|
||||
* Attach to $element (usually attempts) the needed backup structures
|
||||
@@ -200,6 +199,17 @@ abstract class backup_questions_activity_structure_step extends backup_activity_
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abstract structure step to help activities that store question attempt data.
|
||||
*
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class backup_questions_activity_structure_step extends backup_activity_structure_step {
|
||||
use backup_questions_attempt_data_trait;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* backup structure step in charge of calculating the categories to be
|
||||
* included in backup, based in the context being backuped (module/course)
|
||||
|
||||
@@ -34,12 +34,24 @@ defined('MOODLE_INTERNAL') || die();
|
||||
*/
|
||||
abstract class restore_plugin {
|
||||
|
||||
/** @var string */
|
||||
protected $plugintype;
|
||||
/** @var string */
|
||||
protected $pluginname;
|
||||
/** @var string */
|
||||
protected $connectionpoint;
|
||||
/** @var restore_structure_step */
|
||||
protected $step;
|
||||
/** @var restore_course_task|restore_activity_task */
|
||||
protected $task;
|
||||
|
||||
/**
|
||||
* restore_plugin constructor.
|
||||
*
|
||||
* @param string $plugintype
|
||||
* @param string $pluginname
|
||||
* @param restore_structure_step $step
|
||||
*/
|
||||
public function __construct($plugintype, $pluginname, $step) {
|
||||
$this->plugintype = $plugintype;
|
||||
$this->pluginname = $pluginname;
|
||||
@@ -58,9 +70,11 @@ abstract class restore_plugin {
|
||||
$methodname = 'define_' . basename($this->connectionpoint->get_path()) . '_plugin_structure';
|
||||
|
||||
if (method_exists($this, $methodname)) {
|
||||
if ($bluginpaths = $this->$methodname()) {
|
||||
foreach ($bluginpaths as $path) {
|
||||
$path->set_processing_object($this);
|
||||
if ($pluginpaths = $this->$methodname()) {
|
||||
foreach ($pluginpaths as $path) {
|
||||
if ($path->get_processing_object() === null && !$this->step->grouped_parent_exists($path, $paths)) {
|
||||
$path->set_processing_object($this);
|
||||
}
|
||||
$paths[] = $path;
|
||||
}
|
||||
}
|
||||
@@ -258,4 +272,13 @@ abstract class restore_plugin {
|
||||
'plugin_' . $this->plugintype . '_' .
|
||||
$this->pluginname . '_' . basename($this->connectionpoint->get_path()) . $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the task we are part of.
|
||||
*
|
||||
* @return restore_activity_task|restore_course_task the task.
|
||||
*/
|
||||
protected function get_task() {
|
||||
return $this->task;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5323,10 +5323,9 @@ class restore_process_file_aliases_queue extends restore_execution_step {
|
||||
|
||||
|
||||
/**
|
||||
* Abstract structure step, to be used by all the activities using core questions stuff
|
||||
* (like the quiz module), to support qtype plugins, states and sessions
|
||||
* Helper code for use by any plugin that stores question attempt data that it needs to back up.
|
||||
*/
|
||||
abstract class restore_questions_activity_structure_step extends restore_activity_structure_step {
|
||||
trait restore_questions_attempt_data_trait {
|
||||
/** @var array question_attempt->id to qtype. */
|
||||
protected $qtypes = array();
|
||||
/** @var array question_attempt->id to questionid. */
|
||||
@@ -5378,21 +5377,21 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
/**
|
||||
* Process question_usages
|
||||
*/
|
||||
protected function process_question_usage($data) {
|
||||
public function process_question_usage($data) {
|
||||
$this->restore_question_usage_worker($data, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process question_attempts
|
||||
*/
|
||||
protected function process_question_attempt($data) {
|
||||
public function process_question_attempt($data) {
|
||||
$this->restore_question_attempt_worker($data, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process question_attempt_steps
|
||||
*/
|
||||
protected function process_question_attempt_step($data) {
|
||||
public function process_question_attempt_step($data) {
|
||||
$this->restore_question_attempt_step_worker($data, '');
|
||||
}
|
||||
|
||||
@@ -5412,8 +5411,7 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
$oldcontextid = $this->get_task()->get_old_contextid();
|
||||
$data->contextid = $this->get_mappingid('context', $this->task->get_old_contextid());
|
||||
$data->contextid = $this->task->get_contextid();
|
||||
|
||||
// Everything ready, insert (no mapping needed)
|
||||
$newitemid = $DB->insert_record('question_usages', $data);
|
||||
@@ -5569,6 +5567,17 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
$this->add_related_files('question', $filearea, 'question_attempt_step');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abstract structure step to help activities that store question attempt data.
|
||||
*
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class restore_questions_activity_structure_step extends restore_activity_structure_step {
|
||||
use restore_questions_attempt_data_trait;
|
||||
|
||||
/**
|
||||
* Attach below $element (usually attempts) the needed restore_path_elements
|
||||
@@ -5612,7 +5621,7 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
/**
|
||||
* Process the attempt data defined by {@link add_legacy_question_attempt_data()}.
|
||||
* @param object $data contains all the grouped attempt data to process.
|
||||
* @param pbject $quiz data about the activity the attempts belong to. Required
|
||||
* @param object $quiz data about the activity the attempts belong to. Required
|
||||
* fields are (basically this only works for the quiz module):
|
||||
* oldquestions => list of question ids in this activity - using old ids.
|
||||
* preferredbehaviour => the behaviour to use for questionattempts.
|
||||
@@ -5674,7 +5683,7 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
|
||||
$data->uniqueid = $usage->id;
|
||||
$upgrader->save_usage($quiz->preferredbehaviour, $data, $qas,
|
||||
$this->questions_recode_layout($quiz->oldquestions));
|
||||
$this->questions_recode_layout($quiz->oldquestions));
|
||||
}
|
||||
|
||||
protected function find_question_session_and_states($data, $questionid) {
|
||||
@@ -5734,6 +5743,7 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restore completion defaults for each module type
|
||||
*
|
||||
|
||||
@@ -496,9 +496,9 @@ abstract class restore_structure_step extends restore_step {
|
||||
// Now, for each element not having one processing object, if
|
||||
// not child of grouped element, assign $this (the step itself) as processing element
|
||||
// Note method must exist or we'll get one @restore_path_element_exception
|
||||
foreach($paths as $key => $pelement) {
|
||||
foreach ($paths as $pelement) {
|
||||
if ($pelement->get_processing_object() === null && !$this->grouped_parent_exists($pelement, $paths)) {
|
||||
$paths[$key]->set_processing_object($this);
|
||||
$pelement->set_processing_object($this);
|
||||
}
|
||||
// Populate $elementsoldid and $elementsoldid based on available pathelements
|
||||
$this->elementsoldid[$pelement->get_name()] = null;
|
||||
@@ -510,18 +510,22 @@ abstract class restore_structure_step extends restore_step {
|
||||
|
||||
/**
|
||||
* Given one pathelement, return true if grouped parent was found
|
||||
*
|
||||
* @param restore_path_element $pelement the element we are interested in.
|
||||
* @param restore_path_element[] $elements the elements that exist.
|
||||
* @return bool true if this element is inside a grouped parent.
|
||||
*/
|
||||
protected function grouped_parent_exists($pelement, $elements) {
|
||||
public function grouped_parent_exists($pelement, $elements) {
|
||||
foreach ($elements as $element) {
|
||||
if ($pelement->get_path() == $element->get_path()) {
|
||||
continue; // Don't compare against itself
|
||||
continue; // Don't compare against itself.
|
||||
}
|
||||
// If element is grouped and parent of pelement, return true
|
||||
// If element is grouped and parent of pelement, return true.
|
||||
if ($element->is_grouped() and strpos($pelement->get_path() . '/', $element->get_path()) === 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // no grouped parent found
|
||||
return false; // No grouped parent found.
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,37 @@ Feature: Backup and restore of quizzes
|
||||
Then I should see "TF1"
|
||||
And I should see "TF2"
|
||||
|
||||
@javascript
|
||||
Scenario: Backup and restore a course containing a quiz with user data.
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| quiz | Quiz 1 | For testing backup | C1 | quiz1 |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name | questiontext |
|
||||
| Test questions | truefalse | TF1 | First question |
|
||||
| Test questions | truefalse | TF2 | Second question |
|
||||
And quiz "Quiz 1" contains the following questions:
|
||||
| question | page |
|
||||
| TF1 | 1 |
|
||||
| TF2 | 2 |
|
||||
And the following "users" exist:
|
||||
| username |
|
||||
| student |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student | C1 | student |
|
||||
And user "student" has attempted "Quiz 1" with responses:
|
||||
| slot | response |
|
||||
| 1 | True |
|
||||
| 2 | False |
|
||||
When I backup "Course 1" course using this options:
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Schema | Course name | Restored course |
|
||||
Then I should see "Restored course"
|
||||
And I follow "Quiz 1"
|
||||
And I should see "Attempts: 1"
|
||||
|
||||
@javascript @_file_upload
|
||||
Scenario: Restore a Moodle 2.8 quiz backup
|
||||
When I am on "Course 1" course homepage
|
||||
|
||||
Reference in New Issue
Block a user