Skip to content

Commit

Permalink
MDL-22135 - logs restore, course and activities + cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
stronk7 committed Nov 11, 2010
1 parent d2af101 commit 0f66ace
Show file tree
Hide file tree
Showing 49 changed files with 1,392 additions and 2,125 deletions.
4 changes: 2 additions & 2 deletions backup/backup.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ abstract class backup implements checksumable {
const OPERATION_RESTORE ='restore';// We are performing one restore

// Version (to keep CFG->backup_version (and release) updated automatically)
const VERSION = 2010092100;
const RELEASE = '2.0 RC1';
const VERSION = 2010101000;
const RELEASE = '2.0 RC2';
}

/*
Expand Down
68 changes: 0 additions & 68 deletions backup/backuplib.php
Original file line number Diff line number Diff line change
Expand Up @@ -229,74 +229,6 @@ function backup_format_data ($bf,$preferences) {
return fwrite ($bf,end_tag("FORMATDATA",2,true));
}

//Backup log info (time ordered)
function backup_log_info($bf,$preferences) {
global $CFG, $DB;

//Number of records to get in every chunk
$recordset_size = 1000;

$status = true;

//Counter, points to current record
$counter = 0;

//Count records
$count_logs = $DB->count_records("log", array("course"=>$preferences->backup_course));

//Pring logs header
if ($count_logs > 0 ) {
fwrite ($bf,start_tag("LOGS",2,true));
}
while ($counter < $count_logs) {
//Get a chunk of records
$logs = $DB->get_records ("log", array("course"=>$preferences->backup_course),"time","*",$counter,$recordset_size);

//We have logs
if ($logs) {
//Iterate
foreach ($logs as $log) {
//See if it is a valid module to backup
if ($log->module == "course" or
$log->module == "user" or
(array_key_exists($log->module, $preferences->mods) and $preferences->mods[$log->module]->backup == 1)) {
// logs with 'upload' in module field are ignored, there is no restore code anyway
//Begin log tag
fwrite ($bf,start_tag("LOG",3,true));

//Output log tag
fwrite ($bf,full_tag("ID",4,false,$log->id));
fwrite ($bf,full_tag("TIME",4,false,$log->time));
fwrite ($bf,full_tag("USERID",4,false,$log->userid));
fwrite ($bf,full_tag("IP",4,false,$log->ip));
fwrite ($bf,full_tag("MODULE",4,false,$log->module));
fwrite ($bf,full_tag("CMID",4,false,$log->cmid));
fwrite ($bf,full_tag("ACTION",4,false,$log->action));
fwrite ($bf,full_tag("URL",4,false,$log->url));
fwrite ($bf,full_tag("INFO",4,false,$log->info));

//End log tag
fwrite ($bf,end_tag("LOG",3,true));
}
//Do some output
$counter++;
if ($counter % 20 == 0) {
echo ".";
if ($counter % 400 == 0) {
echo "<br />";
}
backup_flush(300);
}
}
}
}
//End logs tag
if ($count_logs > 0 ) {
$status = fwrite ($bf,end_tag("LOGS",2,true));
}
return $status;
}

function backup_gradebook_categories_history_info($bf, $preferences) {
global $CFG, $DB;

Expand Down
2 changes: 1 addition & 1 deletion backup/moodle2/backup_course_task.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function build() {

// Generate the logs file (conditionally)
if ($this->get_setting_value('logs')) {
//$this->add_step(new backup_course_logs_structure_step('course_logs', 'logs.xml'));
$this->add_step(new backup_course_logs_structure_step('course_logs', 'logs.xml'));
}

// Generate the inforef file (must be after ALL steps gathering annotations of ANY type)
Expand Down
38 changes: 37 additions & 1 deletion backup/moodle2/backup_stepslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,42 @@ protected function define_structure() {
}
}

/**
* structure step in charge of constructing the logs.xml file for all the log records found
* in course. Note that we are sending to backup ALL the log records having cmid = 0. That
* includes some records that won't be restoreable (like 'upload', 'calendar'...) but we do
* that just in case they become restored some day in the future
*/
class backup_course_logs_structure_step extends backup_structure_step {

protected function define_structure() {

// Define each element separated

$logs = new backup_nested_element('logs');

$log = new backup_nested_element('log', array('id'), array(
'time', 'userid', 'ip', 'module',
'action', 'url', 'info'));

// Build the tree

$logs->add_child($log);

// Define sources (all the records belonging to the course, having cmid = 0)

$log->set_source_table('log', array('course' => backup::VAR_COURSEID, 'cmid' => backup_helper::is_sqlparam(0)));

// Annotations
// NOTE: We don't annotate users from logs as far as they MUST be
// always annotated by the course (enrol, ras... whatever)

// Return the root element (logs)

return $logs;
}
}

/**
* structure step in charge of constructing the logs.xml file for all the log records found
* in activity
Expand All @@ -1210,7 +1246,7 @@ protected function define_structure() {

// Annotations
// NOTE: We don't annotate users from logs as far as they MUST be
// always annotated by the activity.
// always annotated by the activity (true participants).

// Return the root element (logs)

Expand Down
14 changes: 12 additions & 2 deletions backup/moodle2/restore_activity_task.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ public function build() {
$this->add_step(new restore_userscompletion_structure_step('activity_userscompletion', 'completion.xml'));
}

// TODO: Logs (conditionally)
// Logs (conditionally)
if ($this->get_setting_value('logs')) {
//$this->add_step(new restore_activity_logs_structure_step('activity_logs', 'logs.xml'));
$this->add_step(new restore_activity_logs_structure_step('activity_logs', 'logs.xml'));
}

// At the end, mark it as built
Expand Down Expand Up @@ -228,6 +228,16 @@ static public function define_decode_rules() {
throw new coding_exception('define_decode_rules() method needs to be overridden in each subclass of restore_activity_task');
}

/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* activity logs. It must return one array
* of {@link restore_log_rule} objects
*/
static public function define_restore_log_rules() {
throw new coding_exception('define_restore_log_rules() method needs to be overridden in each subclass of restore_activity_task');
}

// Protected API starts here

/**
Expand Down
5 changes: 0 additions & 5 deletions backup/moodle2/restore_course_task.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,6 @@ public function build() {
$this->add_step(new restore_comments_structure_step('course_comments', 'comments.xml'));
}

// Restore course logs (conditionally)
if ($this->get_setting_value('logs')) {
//$this->add_step(new restore_course_logs_structure_step('course_logs', 'logs.xml'));
}

// At the end, mark it as built
$this->built = true;
}
Expand Down
55 changes: 55 additions & 0 deletions backup/moodle2/restore_final_task.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ public function build() {
// Decode all the interlinks
$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
if ($this->get_setting_value('logs')) {
$this->add_step(new restore_course_logs_structure_step('course_logs', 'course/logs.xml'));
}

// Rebuild course cache to see results, whoah!
$this->add_step(new restore_rebuild_course_cache('rebuild_course_cache'));

Expand All @@ -89,6 +95,55 @@ public function launch_execute_after_restore() {
$this->plan->execute_after_restore();
}

/**
* Define the restore log rules that will be applied
* by the {@link restore_logs_processor} when restoring
* course logs. It must return one array
* of {@link restore_log_rule} objects
*
* Note these are course logs, but are defined and restored
* in final task because we need all the activities to be
* restored in order to handle some log records properly
*/
static public function define_restore_log_rules() {
$rules = array();

// module 'course' rules
$rules[] = new restore_log_rule('course', 'view', 'view.php?id={course}', '{course}');
$rules[] = new restore_log_rule('course', 'guest', 'view.php?id={course}', null);
$rules[] = new restore_log_rule('course', 'user report', 'user.php?id={course}&user={user}&mode=[mode]', null);
$rules[] = new restore_log_rule('course', 'add mod', '../mod/[modname]/view.php?id={course_module}', '[modname] {[modname]}');
$rules[] = new restore_log_rule('course', 'update mod', '../mod/[modname]/view.php?id={course_module}', '[modname] {[modname]}');
$rules[] = new restore_log_rule('course', 'delete mod', 'view.php?id={course}', null);
$rules[] = new restore_log_rule('course', 'update', 'view.php?id={course}', '');
$rules[] = new restore_log_rule('course', 'enrol', 'view.php?id={course}', '{user}');
$rules[] = new restore_log_rule('course', 'unenrol', 'view.php?id={course}', '{user}');
$rules[] = new restore_log_rule('course', 'editsection', 'editsection.php?id={course_section}', null);
$rules[] = new restore_log_rule('course', 'new', 'view.php?id={course}', '');
$rules[] = new restore_log_rule('course', 'recent', 'recent.php?id={course}', '');
$rules[] = new restore_log_rule('course', 'report log', 'report/log/index.php?id={course}', '{course}');
$rules[] = new restore_log_rule('course', 'report live', 'report/live/index.php?id={course}', '{course}');
$rules[] = new restore_log_rule('course', 'report outline', 'report/outline/index.php?id={course}', '{course}');
$rules[] = new restore_log_rule('course', 'report participation', 'report/participation/index.php?id={course}', '{course}');
$rules[] = new restore_log_rule('course', 'report stats', 'report/stats/index.php?id={course}', '{course}');

// module 'user' rules
$rules[] = new restore_log_rule('user', 'view', 'view.php?id={user}&course={course}', '{user}');
$rules[] = new restore_log_rule('user', 'change password', 'view.php?id={user}&course={course}', '{user}');
$rules[] = new restore_log_rule('user', 'login', 'view.php?id={user}&course={course}', '{user}');
$rules[] = new restore_log_rule('user', 'logout', 'view.php?id={user}&course={course}', '{user}');
$rules[] = new restore_log_rule('user', 'view all', 'index.php?id={course}', '');
$rules[] = new restore_log_rule('user', 'update', 'view.php?id={user}&course={course}', '');

// rules from other tasks (activities) not belonging to one module instance (cmid = 0), so are restored here
$rules = array_merge($rules, restore_logs_processor::register_log_rules_for_course());

// TODO: Other logs like 'calendar', 'upload'... will go here

return $rules;
}


// Protected API starts here

/**
Expand Down
118 changes: 118 additions & 0 deletions backup/moodle2/restore_stepslib.php
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,124 @@ public function process_course_completion_aggr_methd($data) {

}


/**
* This structure step restores course logs (cmid = 0), delegating
* the hard work to the corresponding {@link restore_logs_processor} passing the
* collection of {@link restore_log_rule} rules to be observed as they are defined
* by the task. Note this is only executed based in the 'logs' setting.
*
* NOTE: This is executed by final task, to have all the activities already restored
*
* NOTE: Not all course logs are being restored. For now only 'course' and 'user'
* records are. There are others like 'calendar' and 'upload' that will be handled
* later.
*
* NOTE: All the missing actions (not able to be restored) are sent to logs for
* debugging purposes
*/
class restore_course_logs_structure_step extends restore_structure_step {

/**
* Conditionally decide if this step should be executed.
*
* This function checks the following four parameters:
*
* 1. the course/logs.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 course logs
return false;
}

return true;
}

protected function define_structure() {

$paths = array();

// Simple, one plain level of information contains them
$paths[] = new restore_path_element('log', '/logs/log');

return $paths;
}

protected function process_log($data) {
global $DB;

$data = (object)($data);

$data->time = $this->apply_date_offset($data->time);
$data->userid = $this->get_mappingid('user', $data->userid);
$data->course = $this->get_courseid();
$data->cmid = 0;

// For any reason user wasn't remapped ok, stop processing this
if (empty($data->userid)) {
return;
}

// Everything ready, let's delegate to the restore_logs_processor

// Set some fixed values that will save tons of DB requests
$values = array(
'course' => $this->get_courseid());
// Get instance and process log record
$data = restore_logs_processor::get_instance($this->task, $values)->process_log_record($data);

// If we have data, insert it, else something went wrong in the restore_logs_processor
if ($data) {
$DB->insert_record('log', $data);
}
}
}

/**
* This structure step restores activity logs, extending {@link restore_course_logs_structure_step}
* sharing its same structure but modifying the way records are handled
*/
class restore_activity_logs_structure_step extends restore_course_logs_structure_step {

protected function process_log($data) {
global $DB;

$data = (object)($data);

$data->time = $this->apply_date_offset($data->time);
$data->userid = $this->get_mappingid('user', $data->userid);
$data->course = $this->get_courseid();
$data->cmid = $this->task->get_moduleid();

// For any reason user wasn't remapped ok, stop processing this
if (empty($data->userid)) {
return;
}

// Everything ready, let's delegate to the restore_logs_processor

// Set some fixed values that will save tons of DB requests
$values = array(
'course' => $this->get_courseid(),
'course_module' => $this->task->get_moduleid(),
$this->task->get_modulename() => $this->task->get_activityid());
// Get instance and process log record
$data = restore_logs_processor::get_instance($this->task, $values)->process_log_record($data);

// If we have data, insert it, else something went wrong in the restore_logs_processor
if ($data) {
$DB->insert_record('log', $data);
}
}
}

/**
* This structure step restores the grade items associated with one activity
* All the grade items are made child of the "course" grade item but the original
Expand Down
Loading

0 comments on commit 0f66ace

Please sign in to comment.