From ea6c56437a9f081e15152bec0ba655b577d5b449 Mon Sep 17 00:00:00 2001 From: "Eloy Lafuente (stronk7)" Date: Mon, 30 Mar 2015 01:19:01 +0200 Subject: [PATCH] MDL-46455 restore: Implement restore of standard logstore Using standard subplugin support, this commits implements the restore of logstore subplugins in general and the standard logstore is particular. Notes: - TODO: Decide about these 2 pending issues: 1) Some logs are already created (events fired) by the restore process itself. Every time an API is used and it fires events... corresponding (and actual!) logs are created. We need to prevent restore to duplicate them (or, alternatively, stop firing events when restore is happening). 2) There are 2 pieces of information in the logs that, right now, can not be restored, because the process does not know enough to be able to remap that information to its new counterparts. We are talking about objectid and other columns. So we need to specify, in some way understandable by restore, to which existing mappings they correspond to. --- ...tore_tool_log_logstore_subplugin.class.php | 37 ++++++ ...tore_logstore_standard_subplugin.class.php | 115 ++++++++++++++++++ .../moodle2/restore_activity_task.class.php | 3 + backup/moodle2/restore_final_task.class.php | 5 +- backup/moodle2/restore_stepslib.php | 69 +++++++++++ 5 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 admin/tool/log/backup/moodle2/restore_tool_log_logstore_subplugin.class.php create mode 100644 admin/tool/log/store/standard/backup/moodle2/restore_logstore_standard_subplugin.class.php diff --git a/admin/tool/log/backup/moodle2/restore_tool_log_logstore_subplugin.class.php b/admin/tool/log/backup/moodle2/restore_tool_log_logstore_subplugin.class.php new file mode 100644 index 00000000000..2b6ec5450b0 --- /dev/null +++ b/admin/tool/log/backup/moodle2/restore_tool_log_logstore_subplugin.class.php @@ -0,0 +1,37 @@ +. + +/** + * Restore support for tool_log logstore subplugins. + * + * @package tool_log + * @category backup + * @copyright 2015 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Parent class of all the logstore subplugin implementations. + * + * Note: While this intermediate class is not strictly required and all the + * subplugin implementations can extend directly {@link restore_subplugin}, + * it is always recommended to have it, both for better testing and also + * for sharing code between all subplugins. + */ +abstract class restore_tool_log_logstore_subplugin extends restore_subplugin { +} diff --git a/admin/tool/log/store/standard/backup/moodle2/restore_logstore_standard_subplugin.class.php b/admin/tool/log/store/standard/backup/moodle2/restore_logstore_standard_subplugin.class.php new file mode 100644 index 00000000000..8457a900aac --- /dev/null +++ b/admin/tool/log/store/standard/backup/moodle2/restore_logstore_standard_subplugin.class.php @@ -0,0 +1,115 @@ +. + +/** + * Restore implementation for the (tool_log) logstore_standard subplugin. + * + * @package logstore_standard + * @category backup + * @copyright 2015 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +class restore_logstore_standard_subplugin extends restore_tool_log_logstore_subplugin { + + /** + * Returns the subplugin structure to attach to the 'logstore' XML element. + * + * @return restore_path_element[] array of elements to be processed on restore. + */ + protected function define_logstore_subplugin_structure() { + + // If the logstore is not enabled we don't add structures for it. + $enabledlogstores = explode(',', get_config('tool_log', 'enabled_stores')); + if (!in_array('logstore_standard', $enabledlogstores)) { + return array(); // The logstore is not enabled, nothing to restore. + } + + $paths = array(); + + $elename = $this->get_namefor('log'); + $elepath = $this->get_pathfor('/logstore_standard_log'); + $paths[] = new restore_path_element($elename, $elepath); + + return $paths; + } + + /** + * Process logstore_standard_log entries. + * + * This method proceeds to read, complete, remap and, finally, + * discard or save every log entry. + * + * @param array() $data log entry. + */ + public function process_logstore_standard_log($data) { + global $DB; + + $data = (object)$data; + + // Complete the information that does not come from backup. + if (! $data->contextid = $this->get_mappingid('context', $data->contextid)) { + // Something went really wrong, cannot find the context this log belongs to. + return; + } + $context = context::instance_by_id($data->contextid, MUST_EXIST); + $data->contextlevel = $context->contextlevel; + $data->contextinstanceid = $context->instanceid; + $data->courseid = $this->task->get_courseid(); + + // Remap users. + if (! $data->userid = $this->get_mappingid('user', $data->userid)) { + // Something went really wrong, cannot find the user this log belongs to. + return; + } + if (!empty($data->relateduserid)) { // This is optional. + if (! $data->relateduserid = $this->get_mappingid('user', $data->relateduserid)) { + // Something went really wrong, cannot find the relateduserid this log is about. + return; + } + } + if (!empty($data->realuserid)) { // This is optional. + if (! $data->realuserid = $this->get_mappingid('user', $data->realuserid)) { + // Something went really wrong, cannot find the realuserid this log is logged in as. + return; + } + } + + // Roll dates. + $data->timecreated = $this->apply_date_offset($data->timecreated); + + // Revert other to its original php way. + $data->other = unserialize(base64_decode($data->other)); + + // Arrived here, we have both 'objectid' and 'other' to be converted. This is the tricky part. + // Both are pointing to other records id, but the sources are not identified in the + // same way restore mappings work. So we need to delegate them to some resolver that + // will give us the correct restore mapping to be used. + if (!empty($data->objectid)) { + // TODO: Call to the resolver. + return; + } + if (!empty($data->other)) { + // TODO: Call to the resolver. + return; + } + + // Arrived here, everything is now ready to be added to database, let's proceed. + $DB->insert_record('logstore_standard_log', $data); + } +} diff --git a/backup/moodle2/restore_activity_task.class.php b/backup/moodle2/restore_activity_task.class.php index 24a045687cf..116c8e2e432 100644 --- a/backup/moodle2/restore_activity_task.class.php +++ b/backup/moodle2/restore_activity_task.class.php @@ -173,7 +173,10 @@ abstract class restore_activity_task extends restore_task { // Logs (conditionally) if ($this->get_setting_value('logs')) { + // Legacy logs. $this->add_step(new restore_activity_logs_structure_step('activity_logs', 'logs.xml')); + // New log stores. + $this->add_step(new restore_activity_logstores_structure_step('activity_logstores', 'logstores.xml')); } // At the end, mark it as built diff --git a/backup/moodle2/restore_final_task.class.php b/backup/moodle2/restore_final_task.class.php index 124208a48aa..ff0ec6f1956 100644 --- a/backup/moodle2/restore_final_task.class.php +++ b/backup/moodle2/restore_final_task.class.php @@ -82,9 +82,12 @@ class restore_final_task extends restore_task { $this->add_step(new restore_decode_interlinks('decode_interlinks')); // Restore course logs (conditionally). They are restored here because we need all - // the activities to be already restored + // the activities to be already restored. if ($this->get_setting_value('logs')) { + // Legacy logs. $this->add_step(new restore_course_logs_structure_step('course_logs', 'course/logs.xml')); + // New log stores. + $this->add_step(new restore_course_logstores_structure_step('course_logstores', 'course/logstores.xml')); } // Review all the executed tasks having one after_restore method diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php index 6cabaabeac3..a41292dffdf 100644 --- a/backup/moodle2/restore_stepslib.php +++ b/backup/moodle2/restore_stepslib.php @@ -2997,6 +2997,75 @@ class restore_activity_logs_structure_step extends restore_course_logs_structure } } +/** + * Structure step in charge of restoring the logstores.xml file for the course logs. + * + * This restore step will rebuild the logs for all the enabled logstore subplugins supporting + * it, for logs belonging to the course level. + */ +class restore_course_logstores_structure_step extends restore_structure_step { + + /** + * Conditionally decide if this step should be executed. + * + * This function checks the following parameter: + * + * 1. the logstores.xml file exists + * + * @return bool true is safe to execute, false otherwise + */ + protected function execute_condition() { + + // Check it is included in the backup. + $fullpath = $this->task->get_taskbasepath(); + $fullpath = rtrim($fullpath, '/') . '/' . $this->filename; + if (!file_exists($fullpath)) { + // Not found, can't restore logstores.xml information. + return false; + } + + return true; + } + + /** + * Return the elements to be processed on restore of logstores. + * + * @return restore_path_element[] array of elements to be processed on restore. + */ + protected function define_structure() { + + $paths = array(); + + $logstore = new restore_path_element('logstore', '/logstores/logstore'); + $paths[] = $logstore; + + // Add logstore subplugin support to the 'logstore' element. + $this->add_subplugin_structure('logstore', $logstore, 'tool', 'log'); + + return array($logstore); + } + + /** + * Process the 'logstore' element, + * + * Note: This is empty by definition in backup, because stores do not share any + * data between them, so there is nothing to process here. + * + * @param array $data element data + */ + protected function process_logstore($data) { + return; + } +} + +/** + * Structure step in charge of restoring the logstores.xml file for the activity logs. + * + * Note: Activity structure is completely equivalent to the course one, so just extend it. + */ +class restore_activity_logstores_structure_step extends restore_course_logstores_structure_step { +} + /** * Defines the restore step for advanced grading methods attached to the activity module