This commit is contained in:
Eloy Lafuente (stronk7)
2019-10-07 22:25:12 +02:00
7 changed files with 115 additions and 22 deletions
@@ -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.
+14
View File
@@ -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;
+13 -3
View File
@@ -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)
+26 -3
View File
@@ -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;
}
}
+20 -10
View File
@@ -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.
}
/**
+31
View File
@@ -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