mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
Merge branch 'MDL-37761-m' of git://github.com/andrewnicols/moodle
This commit is contained in:
commit
6ef007def6
@ -51,8 +51,25 @@ abstract class backup implements checksumable {
|
||||
|
||||
// Predefined modes (purposes) of the backup
|
||||
const MODE_GENERAL = 10;
|
||||
|
||||
/**
|
||||
* This is used for importing courses, and for duplicating activities.
|
||||
*
|
||||
* This mode will ensure that files are not included in the backup generation, and
|
||||
* during a restore they are copied from the existing file record.
|
||||
*/
|
||||
const MODE_IMPORT = 20;
|
||||
const MODE_HUB = 30;
|
||||
|
||||
/**
|
||||
* This mode is intended for duplicating courses and cases where the backup target is
|
||||
* within the same site.
|
||||
*
|
||||
* This mode will ensure that files are not included in the backup generation, and
|
||||
* during a restore they are copied from the existing file record.
|
||||
*
|
||||
* For creating a backup for archival purposes or greater longevity, use MODE_GENERAL.
|
||||
*/
|
||||
const MODE_SAMESITE = 40;
|
||||
const MODE_AUTOMATED = 50;
|
||||
const MODE_CONVERTED = 60;
|
||||
|
@ -56,6 +56,7 @@ class backup_controller extends backup implements loggable {
|
||||
protected $status; // Current status of the controller (created, planned, configured...)
|
||||
|
||||
protected $plan; // Backup execution plan
|
||||
protected $includefiles; // Whether this backup includes files or not.
|
||||
|
||||
protected $execution; // inmediate/delayed
|
||||
protected $executiontime; // epoch time when we want the backup to be executed (requires cron to run)
|
||||
@ -239,6 +240,17 @@ class backup_controller extends backup implements loggable {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value of the include_files setting.
|
||||
* This setting is intended to ensure that files are not included in
|
||||
* generated backups.
|
||||
*
|
||||
* @return int Indicates whether files should be included in backups.
|
||||
*/
|
||||
public function get_include_files() {
|
||||
return $this->includefiles;
|
||||
}
|
||||
|
||||
public function get_operation() {
|
||||
return $this->operation;
|
||||
}
|
||||
@ -362,6 +374,33 @@ class backup_controller extends backup implements loggable {
|
||||
$this->log('applying plan defaults', backup::LOG_DEBUG);
|
||||
backup_controller_dbops::apply_config_defaults($this);
|
||||
$this->set_status(backup::STATUS_CONFIGURED);
|
||||
$this->set_include_files();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial value for the include_files setting.
|
||||
*
|
||||
* @see backup_controller::get_include_files for further information on the purpose of this setting.
|
||||
* @return int Indicates whether files should be included in backups.
|
||||
*/
|
||||
protected function set_include_files() {
|
||||
// We normally include files.
|
||||
$includefiles = true;
|
||||
|
||||
// In an import, we don't need to include files.
|
||||
if ($this->get_mode() === backup::MODE_IMPORT) {
|
||||
$includefiles = false;
|
||||
}
|
||||
|
||||
// When a backup is intended for the same site, we don't need to include the files.
|
||||
// Note, this setting is only used for duplication of an entire course.
|
||||
if ($this->get_mode() === backup::MODE_SAMESITE) {
|
||||
$includefiles = false;
|
||||
}
|
||||
|
||||
$this->includefiles = (int) $includefiles;
|
||||
$this->log("setting file inclusion to {$this->includefiles}", backup::LOG_DEBUG);
|
||||
return $this->includefiles;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,6 +82,25 @@ class backup_controller_testcase extends advanced_testcase {
|
||||
$newbc = mock_backup_controller::load_controller($bc->get_backupid());
|
||||
$this->assertTrue($newbc instanceof backup_controller); // This means checksum and load worked ok
|
||||
}
|
||||
|
||||
public function test_backup_controller_include_files() {
|
||||
// A MODE_GENERAL controller - this should include files
|
||||
$bc = new mock_backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_GENERAL, $this->userid);
|
||||
$this->assertEquals($bc->get_include_files(), 1);
|
||||
|
||||
|
||||
// The MODE_IMPORT and MODE_SAMESITE should not include files in the backup.
|
||||
// A MODE_IMPORT controller
|
||||
$bc = new mock_backup_controller(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $this->userid);
|
||||
$this->assertEquals($bc->get_include_files(), 0);
|
||||
|
||||
// A MODE_SAMESITE controller
|
||||
$bc = new mock_backup_controller(backup::TYPE_1COURSE, $this->courseid, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $this->userid);
|
||||
$this->assertEquals($bc->get_include_files(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1489,6 +1489,7 @@ class backup_main_structure_step extends backup_structure_step {
|
||||
$info['backup_date'] = time();
|
||||
$info['backup_uniqueid']= $this->get_backupid();
|
||||
$info['mnet_remoteusers']=backup_controller_dbops::backup_includes_mnet_remote_users($this->get_backupid());
|
||||
$info['include_files'] = backup_controller_dbops::backup_includes_files($this->get_backupid());
|
||||
$info['include_file_references_to_external_content'] =
|
||||
backup_controller_dbops::backup_includes_file_references($this->get_backupid());
|
||||
$info['original_wwwroot']=$CFG->wwwroot;
|
||||
@ -1510,7 +1511,7 @@ class backup_main_structure_step extends backup_structure_step {
|
||||
|
||||
$information = new backup_nested_element('information', null, array(
|
||||
'name', 'moodle_version', 'moodle_release', 'backup_version',
|
||||
'backup_release', 'backup_date', 'mnet_remoteusers', 'include_file_references_to_external_content', 'original_wwwroot',
|
||||
'backup_release', 'backup_date', 'mnet_remoteusers', 'include_files', 'include_file_references_to_external_content', 'original_wwwroot',
|
||||
'original_site_identifier_hash', 'original_course_id',
|
||||
'original_course_fullname', 'original_course_shortname', 'original_course_startdate',
|
||||
'original_course_contextid', 'original_system_contextid'));
|
||||
|
@ -395,6 +395,19 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
return (int)(bool)$count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the backupid, determine whether this backup should include
|
||||
* files from the moodle file storage system.
|
||||
*
|
||||
* @param string $backupid The ID of the backup.
|
||||
* @return int Indicates whether files should be included in backups.
|
||||
*/
|
||||
public static function backup_includes_files($backupid) {
|
||||
// Load controller
|
||||
$bc = self::load_controller($backupid);
|
||||
return $bc->get_include_files();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the backupid, detect if the backup contains references to external contents
|
||||
*
|
||||
|
@ -823,6 +823,9 @@ abstract class restore_dbops {
|
||||
public static function send_files_to_pool($basepath, $restoreid, $component, $filearea, $oldcontextid, $dfltuserid, $itemname = null, $olditemid = null, $forcenewcontextid = null, $skipparentitemidctxmatch = false) {
|
||||
global $DB, $CFG;
|
||||
|
||||
$backupinfo = backup_general_helper::get_backup_information(basename($basepath));
|
||||
$includesfiles = $backupinfo->include_files;
|
||||
|
||||
$results = array();
|
||||
|
||||
if ($forcenewcontextid) {
|
||||
@ -900,43 +903,68 @@ abstract class restore_dbops {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The file record to restore.
|
||||
$file_record = array(
|
||||
'contextid' => $newcontextid,
|
||||
'component' => $component,
|
||||
'filearea' => $filearea,
|
||||
'itemid' => $rec->newitemid,
|
||||
'filepath' => $file->filepath,
|
||||
'filename' => $file->filename,
|
||||
'timecreated' => $file->timecreated,
|
||||
'timemodified'=> $file->timemodified,
|
||||
'userid' => $mappeduserid,
|
||||
'author' => $file->author,
|
||||
'license' => $file->license,
|
||||
'sortorder' => $file->sortorder
|
||||
);
|
||||
|
||||
if (empty($file->repositoryid)) {
|
||||
// this is a regular file, it must be present in the backup pool
|
||||
$backuppath = $basepath . backup_file_manager::get_backup_content_file_location($file->contenthash);
|
||||
|
||||
// The file is not found in the backup.
|
||||
if (!file_exists($backuppath)) {
|
||||
$result = new stdClass();
|
||||
$result->code = 'file_missing_in_backup';
|
||||
$result->message = sprintf('missing file %s%s in backup', $file->filepath, $file->filename);
|
||||
$result->level = backup::LOG_WARNING;
|
||||
$results[] = $result;
|
||||
continue;
|
||||
}
|
||||
|
||||
// create the file in the filepool if it does not exist yet
|
||||
if (!$fs->file_exists($newcontextid, $component, $filearea, $rec->newitemid, $file->filepath, $file->filename)) {
|
||||
|
||||
// If no license found, use default.
|
||||
if ($file->license == null){
|
||||
$file->license = $CFG->sitedefaultlicense;
|
||||
// Some file types do not include the files as they should already be
|
||||
// present. We still need to create entries into the files table.
|
||||
if ($includesfiles) {
|
||||
// The file is not found in the backup.
|
||||
if (!file_exists($backuppath)) {
|
||||
$result = new stdClass();
|
||||
$result->code = 'file_missing_in_backup';
|
||||
$result->message = sprintf('missing file %s%s in backup', $file->filepath, $file->filename);
|
||||
$result->level = backup::LOG_WARNING;
|
||||
$results[] = $result;
|
||||
continue;
|
||||
}
|
||||
|
||||
$file_record = array(
|
||||
'contextid' => $newcontextid,
|
||||
'component' => $component,
|
||||
'filearea' => $filearea,
|
||||
'itemid' => $rec->newitemid,
|
||||
'filepath' => $file->filepath,
|
||||
'filename' => $file->filename,
|
||||
'timecreated' => $file->timecreated,
|
||||
'timemodified'=> $file->timemodified,
|
||||
'userid' => $mappeduserid,
|
||||
'author' => $file->author,
|
||||
'license' => $file->license,
|
||||
'sortorder' => $file->sortorder
|
||||
);
|
||||
$fs->create_file_from_pathname($file_record, $backuppath);
|
||||
// create the file in the filepool if it does not exist yet
|
||||
if (!$fs->file_exists($newcontextid, $component, $filearea, $rec->newitemid, $file->filepath, $file->filename)) {
|
||||
|
||||
// If no license found, use default.
|
||||
if ($file->license == null){
|
||||
$file->license = $CFG->sitedefaultlicense;
|
||||
}
|
||||
|
||||
$fs->create_file_from_pathname($file_record, $backuppath);
|
||||
}
|
||||
} else {
|
||||
// This backup does not include the files - they should be available in moodle filestorage already.
|
||||
|
||||
// Even if a file has been deleted since the backup was made, the file metadata will remain in the
|
||||
// files table, and the file will not be moved to the trashdir.
|
||||
// Files are not cleared from the files table by cron until several days after deletion.
|
||||
if ($foundfiles = $DB->get_records('files', array('contenthash' => $file->contenthash))) {
|
||||
// Only grab one of the foundfiles - the file content should be the same for all entries.
|
||||
$foundfile = reset($foundfiles);
|
||||
$fs->create_file_from_storedfile($file_record, $foundfile->id);
|
||||
} else {
|
||||
// A matching existing file record was not found in the database.
|
||||
$result = new stdClass();
|
||||
$result->code = 'file_missing_in_backup';
|
||||
$result->message = sprintf('missing file %s%s in backup', $file->filepath, $file->filename);
|
||||
$result->level = backup::LOG_WARNING;
|
||||
$results[] = $result;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// store the the new contextid and the new itemid in case we need to remap
|
||||
@ -954,20 +982,7 @@ abstract class restore_dbops {
|
||||
// oldfile holds the raw information stored in MBZ (including reference-related info)
|
||||
$info->oldfile = $file;
|
||||
// newfile holds the info for the new file_record with the context, user and itemid mapped
|
||||
$info->newfile = (object)array(
|
||||
'contextid' => $newcontextid,
|
||||
'component' => $component,
|
||||
'filearea' => $filearea,
|
||||
'itemid' => $rec->newitemid,
|
||||
'filepath' => $file->filepath,
|
||||
'filename' => $file->filename,
|
||||
'timecreated' => $file->timecreated,
|
||||
'timemodified'=> $file->timemodified,
|
||||
'userid' => $mappeduserid,
|
||||
'author' => $file->author,
|
||||
'license' => $file->license,
|
||||
'sortorder' => $file->sortorder
|
||||
);
|
||||
$info->newfile = (object) $file_record;
|
||||
|
||||
restore_dbops::set_backup_ids_record($restoreid, 'file_aliases_queue', $file->id, 0, null, $info);
|
||||
}
|
||||
|
@ -148,6 +148,30 @@ class backup_dbops_testcase extends advanced_testcase {
|
||||
backup_controller_dbops::drop_backup_ids_temp_table('testingid');
|
||||
$this->assertFalse($dbman->table_exists('backup_ids_temp'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check backup_includes_files
|
||||
*/
|
||||
function test_backup_controller_dbops_includes_files() {
|
||||
global $DB;
|
||||
|
||||
$dbman = $DB->get_manager(); // Going to use some database_manager services for testing
|
||||
|
||||
// A MODE_GENERAL controller - this should include files
|
||||
$bc = new mock_backup_controller4dbops(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_GENERAL, $this->userid);
|
||||
$this->assertEquals(backup_controller_dbops::backup_includes_files($bc->get_backupid()), 1);
|
||||
|
||||
// A MODE_IMPORT controller - should not include files
|
||||
$bc = new mock_backup_controller4dbops(backup::TYPE_1ACTIVITY, $this->moduleid, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $this->userid);
|
||||
$this->assertEquals(backup_controller_dbops::backup_includes_files($bc->get_backupid()), 0);
|
||||
|
||||
// A MODE_SAMESITE controller - should not include files
|
||||
$bc = new mock_backup_controller4dbops(backup::TYPE_1COURSE, $this->moduleid, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $this->userid);
|
||||
$this->assertEquals(backup_controller_dbops::backup_includes_files($bc->get_backupid()), 0);
|
||||
}
|
||||
}
|
||||
|
||||
class mock_backup_controller4dbops extends backup_controller {
|
||||
|
@ -61,6 +61,11 @@ class backup_file_manager {
|
||||
public static function copy_file_moodle2backup($backupid, $filerecorid) {
|
||||
global $DB;
|
||||
|
||||
if (!backup_controller_dbops::backup_includes_files($backupid)) {
|
||||
// Only include the files if required by the controller.
|
||||
return;
|
||||
}
|
||||
|
||||
// Normalise param
|
||||
if (!is_object($filerecorid)) {
|
||||
$filerecorid = $DB->get_record('files', array('id' => $filerecorid));
|
||||
|
@ -155,6 +155,12 @@ abstract class backup_general_helper extends backup_helper {
|
||||
} else {
|
||||
$info->include_file_references_to_external_content = 0;
|
||||
}
|
||||
// include_files is a new setting in 2.6.
|
||||
if (isset($infoarr['include_files'])) {
|
||||
$info->include_files = $infoarr['include_files'];
|
||||
} else {
|
||||
$info->include_files = 1;
|
||||
}
|
||||
$info->type = $infoarr['details']['detail'][0]['type'];
|
||||
$info->format = $infoarr['details']['detail'][0]['format'];
|
||||
$info->mode = $infoarr['details']['detail'][0]['mode'];
|
||||
|
Loading…
x
Reference in New Issue
Block a user