MDL-34859 backup: add restore defaults

This commit is contained in:
Marina Glancy 2017-02-17 16:21:55 +08:00
parent f840bf03e0
commit 44e86fb3d5
15 changed files with 535 additions and 45 deletions

View File

@ -343,4 +343,105 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
//$temp->add(new admin_setting_configcheckbox('backup/backup_auto_blogs', new lang_string('blogs', 'blog'), new lang_string('backupblogshelp','blog'), 0));
$ADMIN->add('backups', $temp);
// Create a page for general restore configuration and defaults.
$temp = new admin_settingpage('restoregeneralsettings', new lang_string('generalrestoredefaults', 'backup'));
// General restore defaults.
$temp->add(new admin_setting_heading('generalsettings', new lang_string('generalrestoresettings', 'backup'), ''));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_users',
new lang_string('generalusers', 'backup'), new lang_string('configrestoreusers', 'backup'),
array('value' => 1, 'locked' => 0)));
// Can not use actual constants here because we'd need to include 100 of backup/restore files.
$options = [
0/*backup::ENROL_NEVER*/ => get_string('rootsettingenrolments_never', 'backup'),
1/*backup::ENROL_WITHUSERS*/ => get_string('rootsettingenrolments_withusers', 'backup'),
2/*backup::ENROL_ALWAYS*/ => get_string('rootsettingenrolments_always', 'backup'),
];
$temp->add(new admin_setting_configselect_with_lock('restore/restore_general_enrolments',
new lang_string('generalenrolments', 'backup'), new lang_string('configrestoreenrolments', 'backup'),
array('value' => 1/*backup::ENROL_WITHUSERS*/, 'locked' => 0), $options));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_role_assignments',
new lang_string('generalroleassignments', 'backup'),
new lang_string('configrestoreroleassignments', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_activities',
new lang_string('generalactivities', 'backup'),
new lang_string('configrestoreactivities', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_blocks',
new lang_string('generalblocks', 'backup'),
new lang_string('configrestoreblocks', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_filters',
new lang_string('generalfilters', 'backup'),
new lang_string('configrestorefilters', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_comments',
new lang_string('generalcomments', 'backup'),
new lang_string('configrestorecomments', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_badges',
new lang_string('generalbadges', 'backup'),
new lang_string('configrestorebadges', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_calendarevents',
new lang_string('generalcalendarevents', 'backup'),
new lang_string('configrestorecalendarevents', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_userscompletion',
new lang_string('generaluserscompletion', 'backup'),
new lang_string('configrestoreuserscompletion', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_logs',
new lang_string('generallogs', 'backup'),
new lang_string('configrestorelogs', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_histories',
new lang_string('generalhistories', 'backup'),
new lang_string('configrestorehistories', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_groups',
new lang_string('generalgroups', 'backup'), new lang_string('configrestoregroups', 'backup'),
array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_competencies',
new lang_string('generalcompetencies', 'backup'),
new lang_string('configrestorecompetencies', 'backup'), array('value' => 1, 'locked' => 0)));
// Restore defaults when merging into another course.
$temp->add(new admin_setting_heading('mergerestoredefaults', new lang_string('mergerestoredefaults', 'backup'), ''));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_merge_overwrite_conf',
new lang_string('setting_overwrite_conf', 'backup'),
new lang_string('config_overwrite_conf', 'backup'), array('value' => 0, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_merge_course_fullname',
new lang_string('setting_overwrite_course_fullname', 'backup'),
new lang_string('config_overwrite_course_fullname', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_merge_course_shortname',
new lang_string('setting_overwrite_course_shortname', 'backup'),
new lang_string('config_overwrite_course_shortname', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_merge_course_startdate',
new lang_string('setting_overwrite_course_startdate', 'backup'),
new lang_string('config_overwrite_course_startdate', 'backup'), array('value' => 1, 'locked' => 0)));
// Restore defaults when replacing course contents.
$temp->add(new admin_setting_heading('replacerestoredefaults', new lang_string('replacerestoredefaults', 'backup'), ''));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_replace_overwrite_conf',
new lang_string('setting_overwrite_conf', 'backup'),
new lang_string('config_overwrite_conf', 'backup'), array('value' => 0, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_replace_course_fullname',
new lang_string('setting_overwrite_course_fullname', 'backup'),
new lang_string('config_overwrite_course_fullname', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_replace_course_shortname',
new lang_string('setting_overwrite_course_shortname', 'backup'),
new lang_string('config_overwrite_course_shortname', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_replace_course_startdate',
new lang_string('setting_overwrite_course_startdate', 'backup'),
new lang_string('config_overwrite_course_startdate', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configselect_with_lock('restore/restore_replace_keep_roles_and_enrolments',
new lang_string('setting_keep_roles_and_enrolments', 'backup'),
new lang_string('config_keep_roles_and_enrolments', 'backup'), array('value' => 0, 'locked' => 0),
array(1 => get_string('yes'), 0 => get_string('no'))));
$temp->add(new admin_setting_configselect_with_lock('restore/restore_replace_keep_groups_and_groupings',
new lang_string('setting_keep_groups_and_groupings', 'backup'),
new lang_string('config_keep_groups_and_groupings', 'backup'), array('value' => 0, 'locked' => 0),
array(1 => get_string('yes'), 0 => get_string('no'))));
$ADMIN->add('backups', $temp);
}

View File

@ -741,6 +741,33 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
$this->assertTrue($found);
}
/**
* Test that specifying course template respects default restore settings
*/
public function test_restore_file_settings() {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
// Set admin config setting so that activities are not restored by default.
set_config('restore_general_activities', 0, 'restore');
$c1 = $this->getDataGenerator()->create_course();
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
$data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname);
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
$this->assertTrue($co->prepare());
$co->proceed();
$course = $DB->get_record('course', array('shortname' => 'A1'));
// Make sure the glossary is not restored.
$modinfo = get_fast_modinfo($course);
$this->assertEmpty($modinfo->get_instances_of('glossary'));
}
public function test_restore_invalid_file() {
$this->resetAfterTest();

View File

@ -142,6 +142,9 @@ class restore_controller extends base_controller {
// Load plan
$this->load_plan();
// Apply all default settings (based on type/format/mode).
$this->apply_defaults();
// Perform all initial security checks and apply (2nd param) them to settings automatically
restore_check::check_security($this, true);
@ -510,6 +513,15 @@ class restore_controller extends base_controller {
$this->plan->build(); // Build plan for this controller
$this->set_status(backup::STATUS_PLANNED);
}
/**
* Apply defaults from the global admin settings
*/
protected function apply_defaults() {
$this->log('applying restore defaults', backup::LOG_DEBUG);
restore_controller_dbops::apply_config_defaults($this);
$this->set_status(backup::STATUS_CONFIGURED);
}
}
/*

View File

@ -162,17 +162,37 @@ class restore_course_task extends restore_task {
*/
protected function define_settings() {
//$name, $vtype, $value = null, $visibility = self::VISIBLE, $status = self::NOT_LOCKED
$fullname = new restore_course_generic_text_setting('course_fullname', base_setting::IS_TEXT, $this->get_info()->original_course_fullname);
$fullname->get_ui()->set_label(get_string('setting_course_fullname', 'backup'));
// Define overwrite_conf to decide if course configuration will be restored over existing one.
$overwrite = new restore_course_overwrite_conf_setting('overwrite_conf', base_setting::IS_BOOLEAN, false);
$overwrite->set_ui(new backup_setting_ui_select($overwrite, $overwrite->get_name(),
array(1 => get_string('yes'), 0 => get_string('no'))));
$overwrite->get_ui()->set_label(get_string('setting_overwrite_conf', 'backup'));
if ($this->get_target() == backup::TARGET_NEW_COURSE) {
$overwrite->set_value(true);
$overwrite->set_status(backup_setting::LOCKED_BY_CONFIG);
$overwrite->set_visibility(backup_setting::HIDDEN);
$course = (object)['fullname' => null, 'shortname' => null, 'startdate' => null];
} else {
$course = get_course($this->get_courseid());
}
$this->add_setting($overwrite);
$fullnamedefaultvalue = $this->get_info()->original_course_fullname;
$fullname = new restore_course_defaultcustom_setting('course_fullname', base_setting::IS_TEXT, $fullnamedefaultvalue);
$fullname->set_ui(new backup_setting_ui_defaultcustom($fullname, get_string('setting_course_fullname', 'backup'),
['customvalue' => $fullnamedefaultvalue, 'defaultvalue' => $course->fullname]));
$this->add_setting($fullname);
$shortname = new restore_course_generic_text_setting('course_shortname', base_setting::IS_TEXT, $this->get_info()->original_course_shortname);
$shortname->get_ui()->set_label(get_string('setting_course_shortname', 'backup'));
$shortnamedefaultvalue = $this->get_info()->original_course_shortname;
$shortname = new restore_course_defaultcustom_setting('course_shortname', base_setting::IS_TEXT, $shortnamedefaultvalue);
$shortname->set_ui(new backup_setting_ui_defaultcustom($shortname, get_string('setting_course_shortname', 'backup'),
['customvalue' => $shortnamedefaultvalue, 'defaultvalue' => $course->shortname]));
$this->add_setting($shortname);
$startdate = new restore_course_generic_text_setting('course_startdate', base_setting::IS_INTEGER, $this->get_info()->original_course_startdate);
$startdate->set_ui(new backup_setting_ui_dateselector($startdate, get_string('setting_course_startdate', 'backup')));
$startdatedefaultvalue = $this->get_info()->original_course_startdate;
$startdate = new restore_course_defaultcustom_setting('course_startdate', base_setting::IS_INTEGER, $startdatedefaultvalue);
$startdate->set_ui(new backup_setting_ui_defaultcustom($startdate, get_string('setting_course_startdate', 'backup'),
['customvalue' => $startdatedefaultvalue, 'defaultvalue' => $course->startdate, 'type' => 'date_selector']));
$this->add_setting($startdate);
$keep_enrols = new restore_course_generic_setting('keep_roles_and_enrolments', base_setting::IS_BOOLEAN, false);
@ -195,16 +215,5 @@ class restore_course_task extends restore_task {
}
$this->add_setting($keep_groups);
// Define overwrite_conf to decide if course configuration will be restored over existing one
$overwrite = new restore_course_overwrite_conf_setting('overwrite_conf', base_setting::IS_BOOLEAN, false);
$overwrite->set_ui(new backup_setting_ui_select($overwrite, $overwrite->get_name(), array(1=>get_string('yes'), 0=>get_string('no'))));
$overwrite->get_ui()->set_label(get_string('setting_overwriteconf', 'backup'));
if ($this->get_target() == backup::TARGET_NEW_COURSE) {
$overwrite->set_value(true);
$overwrite->set_status(backup_setting::LOCKED_BY_CONFIG);
$overwrite->set_visibility(backup_setting::HIDDEN);
}
$this->add_setting($overwrite);
}
}

View File

@ -143,6 +143,41 @@ class restore_course_generic_setting extends course_backup_setting {}
*/
class restore_course_overwrite_conf_setting extends restore_course_generic_setting {}
/**
* Setting to switch between current and new course name/startdate
*
* @copyright 2017 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class restore_course_defaultcustom_setting extends restore_course_generic_setting {
/**
* Validates that the value $value has type $vtype
* @param int $vtype
* @param mixed $value
* @return mixed
*/
public function validate_value($vtype, $value) {
if ($value === false) {
// Value "false" means default and is allowed for this setting type even if it does not match $vtype.
return $value;
}
return parent::validate_value($vtype, $value);
}
/**
* Special method for this element only. When value is "false" returns the default value.
* @return mixed
*/
public function get_normalized_value() {
$value = $this->get_value();
if ($value === false && $this->get_ui() instanceof backup_setting_ui_defaultcustom) {
$attributes = $this->get_ui()->get_attributes();
return $attributes['defaultvalue'];
}
return $value;
}
}
class restore_course_generic_text_setting extends restore_course_generic_setting {

View File

@ -1810,36 +1810,30 @@ class restore_course_structure_step extends restore_structure_step {
$context = context::instance_by_id($this->task->get_contextid());
$userid = $this->task->get_userid();
$target = $this->get_task()->get_target();
$isnewcourse = $target != backup::TARGET_CURRENT_ADDING && $target != backup::TARGET_EXISTING_ADDING;
$isnewcourse = $target == backup::TARGET_NEW_COURSE;
// When restoring to a new course we can set all the things except for the ID number.
$canchangeidnumber = $isnewcourse || has_capability('moodle/course:changeidnumber', $context, $userid);
$canchangeshortname = $isnewcourse || has_capability('moodle/course:changeshortname', $context, $userid);
$canchangefullname = $isnewcourse || has_capability('moodle/course:changefullname', $context, $userid);
$canchangesummary = $isnewcourse || has_capability('moodle/course:changesummary', $context, $userid);
$data = (object)$data;
$data->id = $this->get_courseid();
// Calculate final course names, to avoid dupes.
$fullname = $this->get_setting_value('course_fullname');
$shortname = $this->get_setting_value('course_shortname');
$startdate = $this->get_setting_value('course_startdate');
// Calculate final course names, to avoid dupes.
list($fullname, $shortname) = restore_dbops::calculate_course_names($this->get_courseid(), $fullname, $shortname);
if ($canchangefullname) {
$data->fullname = $fullname;
} else {
list($data->fullname, $data->shortname) = restore_dbops::calculate_course_names($this->get_courseid(),
$fullname === false ? $data->fullname : $fullname,
$shortname === false ? $data->shortname : $shortname);
// Do not modify the course names at all when merging and user selected to keep the names (or prohibited by cap).
if (!$isnewcourse && $fullname === false) {
unset($data->fullname);
}
if ($canchangeshortname) {
$data->shortname = $shortname;
} else {
if (!$isnewcourse && $shortname === false) {
unset($data->shortname);
}
// Unset summary if user can't change it.
if (!$canchangesummary) {
unset($data->summary);
unset($data->summaryformat);

View File

@ -176,6 +176,8 @@ abstract class restore_check {
if (!$hasrolldatescap) {
$startdatesetting = $restore_controller->get_plan()->get_setting('course_startdate');
if ($startdatesetting) {
$startdatesetting->set_status(base_setting::NOT_LOCKED); // Permission lock overrides config lock.
$startdatesetting->set_value(false);
$startdatesetting->set_status(base_setting::LOCKED_BY_PERMISSION);
}
}
@ -185,6 +187,8 @@ abstract class restore_check {
$haschangefullnamecap = has_capability('moodle/course:changefullname', $coursectx, $userid);
if (!$haschangefullnamecap) {
$fullnamesetting = $restore_controller->get_plan()->get_setting('course_fullname');
$fullnamesetting->set_status(base_setting::NOT_LOCKED); // Permission lock overrides config lock.
$fullnamesetting->set_value(false);
$fullnamesetting->set_status(base_setting::LOCKED_BY_PERMISSION);
}
@ -193,6 +197,8 @@ abstract class restore_check {
$haschangeshortnamecap = has_capability('moodle/course:changeshortname', $coursectx, $userid);
if (!$haschangeshortnamecap) {
$shortnamesetting = $restore_controller->get_plan()->get_setting('course_shortname');
$shortnamesetting->set_status(base_setting::NOT_LOCKED); // Permission lock overrides config lock.
$shortnamesetting->set_value(false);
$shortnamesetting->set_status(base_setting::LOCKED_BY_PERMISSION);
}
@ -201,6 +207,8 @@ abstract class restore_check {
$hasupdatecap = has_capability('moodle/course:update', $coursectx, $userid);
if (!$hasupdatecap) {
$overwritesetting = $restore_controller->get_plan()->get_setting('overwrite_conf');
$overwritesetting->set_status(base_setting::NOT_LOCKED); // Permission lock overrides config lock.
$overwritesetting->set_value(false);
$overwritesetting->set_status(base_setting::LOCKED_BY_PERMISSION);
}

View File

@ -134,4 +134,132 @@ abstract class restore_controller_dbops extends restore_dbops {
// Invalidate the backup_ids caches.
restore_dbops::reset_backup_ids_cached();
}
/**
* Sets the default values for the settings in a restore operation
*
* @param restore_controller $controller
*/
public static function apply_config_defaults(restore_controller $controller) {
$settings = array(
'restore_general_users' => 'users',
'restore_general_enrolments' => 'enrolments',
'restore_general_role_assignments' => 'role_assignments',
'restore_general_activities' => 'activities',
'restore_general_blocks' => 'blocks',
'restore_general_filters' => 'filters',
'restore_general_comments' => 'comments',
'restore_general_badges' => 'badges',
'restore_general_calendarevents' => 'calendarevents',
'restore_general_userscompletion' => 'userscompletion',
'restore_general_logs' => 'logs',
'restore_general_histories' => 'grade_histories',
'restore_general_questionbank' => 'questionbank',
'restore_general_groups' => 'groups',
'restore_general_competencies' => 'competencies'
);
self::apply_admin_config_defaults($controller, $settings, true);
$target = $controller->get_target();
if ($target == backup::TARGET_EXISTING_ADDING || $target == backup::TARGET_CURRENT_ADDING) {
$settings = array(
'restore_merge_overwrite_conf' => 'overwrite_conf',
'restore_merge_course_fullname' => 'course_fullname',
'restore_merge_course_shortname' => 'course_shortname',
'restore_merge_course_startdate' => 'course_startdate',
);
self::apply_admin_config_defaults($controller, $settings, true);
}
if ($target == backup::TARGET_EXISTING_DELETING || $target == backup::TARGET_CURRENT_DELETING) {
$settings = array(
'restore_replace_overwrite_conf' => 'overwrite_conf',
'restore_replace_course_fullname' => 'course_fullname',
'restore_replace_course_shortname' => 'course_shortname',
'restore_replace_course_startdate' => 'course_startdate',
'restore_replace_keep_roles_and_enrolments' => 'keep_roles_and_enrolments',
'restore_replace_keep_groups_and_groupings' => 'keep_groups_and_groupings',
);
self::apply_admin_config_defaults($controller, $settings, true);
}
// Add some dependencies.
$plan = $controller->get_plan();
if ($plan->setting_exists('overwrite_conf')) {
/** @var restore_course_overwrite_conf_setting $overwriteconf */
$overwriteconf = $plan->get_setting('overwrite_conf');
if ($overwriteconf->get_visibility()) {
foreach (['course_fullname', 'course_shortname', 'course_startdate'] as $settingname) {
if ($plan->setting_exists($settingname)) {
$setting = $plan->get_setting($settingname);
$overwriteconf->add_dependency($setting, setting_dependency::DISABLED_FALSE,
array('defaultvalue' => $setting->get_value()));
}
}
}
}
}
/**
* Returns the default value to be used for a setting from the admin restore config
*
* @param string $config
* @param backup_setting $setting
* @return mixed
*/
private static function get_setting_default($config, $setting) {
$value = get_config('restore', $config);
if (in_array($setting->get_name(), ['course_fullname', 'course_shortname', 'course_startdate']) &&
$setting->get_ui() instanceof backup_setting_ui_defaultcustom) {
// Special case - admin config settings course_fullname, etc. are boolean and the restore settings are strings.
$value = (bool)$value;
if ($value) {
$attributes = $setting->get_ui()->get_attributes();
$value = $attributes['customvalue'];
}
}
if ($setting->get_ui() instanceof backup_setting_ui_select) {
// Make sure the value is a valid option in the select element, otherwise just pick the first from the options list.
// Example: enrolments dropdown may not have the "enrol_withusers" option because users info can not be restored.
$options = array_keys($setting->get_ui()->get_values());
if (!in_array($value, $options)) {
$value = reset($options);
}
}
return $value;
}
/**
* Sets the controller settings default values from the admin config.
*
* @param restore_controller $controller
* @param array $settings a map from admin config names to setting names (Config name => Setting name)
* @param boolean $uselocks whether "locked" admin settings should be honoured
*/
private static function apply_admin_config_defaults(restore_controller $controller, array $settings, $uselocks) {
$plan = $controller->get_plan();
foreach ($settings as $config => $settingname) {
if ($plan->setting_exists($settingname)) {
$setting = $plan->get_setting($settingname);
$value = self::get_setting_default($config, $setting);
$locked = (get_config('restore', $config . '_locked') == true);
// We can only update the setting if it isn't already locked by config or permission.
if ($setting->get_status() != base_setting::LOCKED_BY_CONFIG
&& $setting->get_status() != base_setting::LOCKED_BY_PERMISSION
&& $setting->get_ui()->is_changeable()) {
$setting->set_value($value);
if ($uselocks && $locked) {
$setting->set_status(base_setting::LOCKED_BY_CONFIG);
}
}
} else {
$controller->log('Unknown setting: ' . $settingname, BACKUP::LOG_DEBUG);
}
}
}
}

View File

@ -113,6 +113,7 @@ abstract class base_plan implements checksumable, executable {
* that are, by definition, unique by name.
*
* @param string $name name of the setting
* @return base_setting
* @throws base_plan_exception if setting name is not found.
*/
public function get_setting($name) {

View File

@ -70,7 +70,12 @@ abstract class restore_step extends base_step {
$original = $this->task->get_info()->original_course_startdate;
$setting = 0;
if ($this->setting_exists('course_startdate')) { // Seting may not exist (MDL-25019).
$setting = $this->get_setting_value('course_startdate');
$settingobject = $this->task->get_setting('course_startdate');
if (method_exists($settingobject, 'get_normalized_value')) {
$setting = $settingobject->get_normalized_value();
} else {
$setting = $settingobject->get_value();
}
}
if (empty($original) || empty($setting)) {
@ -81,11 +86,6 @@ abstract class restore_step extends base_step {
// Less than 24h of difference, offset = 0 (this avoids some problems with timezones).
$cache[$this->get_restoreid()] = 0;
} else if (!has_capability('moodle/restore:rolldates',
context_course::instance($this->get_courseid()), $this->task->get_userid())) {
// Re-enforce 'moodle/restore:rolldates' capability for the user in the course, just in case.
$cache[$this->get_restoreid()] = 0;
} else {
// Arrived here, let's calculate the real offset.
$cache[$this->get_restoreid()] = $setting - $original;

View File

@ -644,6 +644,14 @@ class backup_setting_ui_select extends backup_setting_ui {
return parent::is_changeable();
}
}
/**
* Returns the list of available values
* @return array
*/
public function get_values() {
return $this->values;
}
}
/**
@ -683,6 +691,58 @@ class backup_setting_ui_dateselector extends backup_setting_ui_text {
}
}
/**
* A wrapper for defaultcustom form element - can have either text or date_selector type
*
* @package core_backup
* @copyright 2017 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_setting_ui_defaultcustom extends backup_setting_ui_text {
/**
* Constructor
*
* @param backup_setting $setting
* @param string $label The label to display with the setting ui
* @param array $attributes Array of HTML attributes to apply to the element
* @param array $options Array of options to apply to the setting ui object
*/
public function __construct(backup_setting $setting, $label = null, array $attributes = null, array $options = null) {
if (!is_array($attributes)) {
$attributes = [];
}
$attributes += ['customlabel' => get_string('overwrite', 'backup'),
'type' => 'text'];
parent::__construct($setting, $label, $attributes, $options);
}
/**
* Returns an array of properties suitable for generating a quickforms element
* @param base_task $task
* @param renderer_base $output
* @return array (element, name, label, options, attributes)
*/
public function get_element_properties(base_task $task = null, renderer_base $output = null) {
return ['element' => 'defaultcustom'] + parent::get_element_properties($task, $output);
}
/**
* Gets the static value for this select element
* @return string
*/
public function get_static_value() {
$value = $this->get_value();
if ($value === false) {
$value = $this->attributes['defaultvalue'];
}
if (!empty($value) && $this->attributes['type'] === 'date_selector') {
return userdate($value);
}
return $value;
}
}
/**
* Base setting UI exception class.
*

View File

@ -317,7 +317,7 @@ abstract class base_ui {
* Gets the requested setting
* @param string $name
* @param bool $default
* @return mixed
* @return base_setting
*/
public function get_setting($name, $default = false) {
try {

View File

@ -98,7 +98,7 @@ class core_course_restore_testcase extends advanced_testcase {
$rc = new restore_controller($backupid, $courseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $userid, $target);
$target == backup::TARGET_NEW_COURSE ?: $rc->get_plan()->get_setting('overwrite_conf')->set_value(true);
$rc->execute_precheck();
$this->assertTrue($rc->execute_precheck());
$rc->execute_plan();
$course = $DB->get_record('course', array('id' => $rc->get_courseid()));
@ -222,7 +222,10 @@ class core_course_restore_testcase extends advanced_testcase {
$this->resetAfterTest();
$dg = $this->getDataGenerator();
$c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
$startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
$c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'startdate' => $startdate,
'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
$backupid = $this->backup_course($c1->id);
// The information is restored but adapted because names are already taken.
@ -231,6 +234,7 @@ class core_course_restore_testcase extends advanced_testcase {
$this->assertEquals('FN copy 1', $c2->fullname);
$this->assertEquals('DESC', $c2->summary);
$this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
$this->assertEquals($startdate, $c2->startdate);
}
public function test_restore_course_info_in_existing_course() {
@ -238,8 +242,19 @@ class core_course_restore_testcase extends advanced_testcase {
$this->resetAfterTest();
$dg = $this->getDataGenerator();
$c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
$c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN]);
$this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
$this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
$this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
$startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
// Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
$c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
'startdate' => $startdate]);
$chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
$c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
'startdate' => $startdate + 2 * WEEKSECS]);
$chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
$backupid = $this->backup_course($c1->id);
// The information is restored but adapted because names are already taken.
@ -248,6 +263,14 @@ class core_course_restore_testcase extends advanced_testcase {
$this->assertEquals('FN copy 1', $c2->fullname);
$this->assertEquals('DESC', $c2->summary);
$this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
$this->assertEquals($startdate, $c2->startdate);
// Now course c2 has two chats - one ('Second') was already there and one ('First') was restored from the backup.
// Their dates are exactly the same as they were in the original modules.
$restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
$restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
$this->assertEquals($chat1->chattime, $restoredchat1->chattime);
$this->assertEquals($chat2->chattime, $restoredchat2->chattime);
}
public function test_restore_course_shortname_in_existing_course_without_permissions() {
@ -321,4 +344,44 @@ class core_course_restore_testcase extends advanced_testcase {
$this->assertEquals($c2->summary, $restored->summary);
$this->assertEquals($c2->summaryformat, $restored->summaryformat);
}
public function test_restore_course_startdate_in_existing_course_without_permissions() {
global $DB;
$this->resetAfterTest();
$dg = $this->getDataGenerator();
$u1 = $dg->create_user();
$managers = get_archetype_roles('manager');
$manager = array_shift($managers);
$roleid = $this->create_role_with_caps('moodle/restore:rolldates', CAP_PROHIBIT);
$dg->role_assign($manager->id, $u1->id);
$dg->role_assign($roleid, $u1->id);
// Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
$startdate1 = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
$startdate2 = mktime(12, 0, 0, 1, 13, 2000); // 13-Jan-2000.
$c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
'startdate' => $startdate1]);
$chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
$c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
'startdate' => $startdate2]);
$chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
// The startdate does not change.
$backupid = $this->backup_course($c1->id);
$restored = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
$this->assertEquals('SN_1', $restored->shortname);
$this->assertEquals('FN copy 1', $restored->fullname);
$this->assertEquals('DESC', $restored->summary);
$this->assertEquals(FORMAT_MOODLE, $restored->summaryformat);
$this->assertEquals($startdate2, $restored->startdate);
// Now course c2 has two chats - one ('Second') was already there and one ('First') was restored from the backup.
// Start date of the restored chat ('First') was changed to be 1 week after the c2 start date.
$restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
$restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
$this->assertNotEquals($chat1->chattime, $restoredchat1->chattime);
$this->assertEquals($chat2->chattime, $restoredchat2->chattime);
$this->assertEquals($c2->startdate + 1 * WEEKSECS, $restoredchat2->chattime);
}
}

View File

@ -83,6 +83,12 @@ $string['choosefilefromactivitybackup'] = 'Activity backup area';
$string['choosefilefromactivitybackup_help'] = 'Activity backups made using default settings are stored here.';
$string['choosefilefromautomatedbackup'] = 'Automated backups';
$string['choosefilefromautomatedbackup_help'] = 'Contains automatically generated backups.';
$string['config_keep_groups_and_groupings'] = 'By default keep current roles and enrolments';
$string['config_keep_roles_and_enrolments'] = 'By default keep current groups and groupings';
$string['config_overwrite_conf'] = 'Allows user to overwrite the current course configuration';
$string['config_overwrite_course_fullname'] = 'By default overwrite course full name with the one from the backup file. This requires "Overwrite course configuration" to be checked and current user to have the capability to change course full name (moodle/course:changefullname)';
$string['config_overwrite_course_shortname'] = 'By default overwrite course short name with the one from the backup file. This requires "Overwrite course configuration" to be checked and current user to have the capability to change course short name (moodle/course:changeshortname)';
$string['config_overwrite_course_startdate'] = 'By default overwrite course start date with the one from the backup file. This requires "Overwrite course configuration" to be checked and current user to have the capability to roll course dates on restore (moodle/restore:rolldates)';
$string['configgeneralactivities'] = 'Sets the default for including activities in a backup.';
$string['configgeneralbadges'] = 'Sets the default for including badges in a backup.';
$string['configgeneralanonymize'] = 'If enabled all information pertaining to users will be anonymised by default.';
@ -99,6 +105,20 @@ $string['configgeneralroleassignments'] = 'If enabled by default roles assignmen
$string['configgeneraluserscompletion'] = 'If enabled user completion information will be included in backups by default.';
$string['configgeneralusers'] = 'Sets the default for whether to include users in backups.';
$string['configloglifetime'] = 'This specifies the length of time you want to keep backup logs information. Logs that are older than this age are automatically deleted. It is recommended to keep this value small, because backup logged information can be huge.';
$string['configrestoreactivities'] = 'Sets the default for restoring activities.';
$string['configrestorebadges'] = 'Sets the default for restoring badges.';
$string['configrestoreblocks'] = 'Sets the default for restoring blocks.';
$string['configrestorecalendarevents'] = 'Sets the default for restoring calendar events.';
$string['configrestorecomments'] = 'Sets the default for restoring comments.';
$string['configrestorecompetencies'] = 'Sets the default for restoring competencies.';
$string['configrestoreenrolments'] = 'Sets the default for restoring enrolment methods.';
$string['configrestorefilters'] = 'Sets the default for restoring filters.';
$string['configrestorehistories'] = 'Sets the default for restoring user history if it was included in the backup.';
$string['configrestorelogs'] = 'If enabled logs will be restored by default if they were included in the backup.';
$string['configrestoregroups'] = 'Sets the default for restoring groups and groupings if they were included in the backup.';
$string['configrestoreroleassignments'] = 'If enabled by default roles assignments will be restored if they were included in the backup.';
$string['configrestoreuserscompletion'] = 'If enabled user completion information will be restored by default if it was included in the backup.';
$string['configrestoreusers'] = 'Sets the default for whether to restore users if they were included in the backup.';
$string['confirmcancel'] = 'Cancel backup';
$string['confirmcancelquestion'] = 'Are you sure you wish to cancel?
Any information you have entered will be lost.';
@ -144,12 +164,17 @@ $string['generalblocks'] = 'Include blocks';
$string['generalcalendarevents'] = 'Include calendar events';
$string['generalcomments'] = 'Include comments';
$string['generalcompetencies'] = 'Include competencies';
$string['generalenrolments'] = 'Include enrolment methods';
$string['generalfilters'] = 'Include filters';
$string['generalhistories'] = 'Include histories';
$string['generalgradehistories'] = 'Include histories';
$string['generallogs'] = 'Include logs';
$string['generalquestionbank'] = 'Include question bank';
$string['generalgroups'] = 'Include groups and groupings';
$string['generalrestoredefaults'] = 'General restore defaults';
$string['mergerestoredefaults'] = 'Restore defaults when merging into another course';
$string['replacerestoredefaults'] = 'Restore defaults when restoring into another course deleting contents';
$string['generalrestoresettings'] = 'General restore settings';
$string['generalroleassignments'] = 'Include role assignments';
$string['generalsettings'] = 'General backup settings';
$string['generaluserscompletion'] = 'Include user completion information';
@ -180,6 +205,7 @@ $string['includesection'] = 'Section {$a}';
$string['includeuserinfo'] = 'User data';
$string['includefilereferences'] = 'File references to external contents';
$string['jumptofinalstep'] = 'Jump to final step';
$string['keep'] = 'Keep';
$string['locked'] = 'Locked';
$string['lockedbypermission'] = 'You don\'t have sufficient permissions to change this setting';
$string['lockedbyconfig'] = 'This setting has been locked by the default backup settings';
@ -192,6 +218,7 @@ $string['moreresults'] = 'There are too many results, enter a more specific sear
$string['nomatchingcourses'] = 'There are no courses to display';
$string['norestoreoptions'] = 'There are no categories or existing courses you can restore to.';
$string['originalwwwroot'] = 'URL of backup';
$string['overwrite'] = 'Overwrite';
$string['previousstage'] = 'Previous';
$string['preparingui'] = 'Preparing to display page';
$string['preparingdata'] = 'Preparing data';
@ -267,12 +294,15 @@ $string['sectioninc'] = 'Included in backup (no user information)';
$string['sectionactivities'] = 'Activities';
$string['selectacategory'] = 'Select a category';
$string['selectacourse'] = 'Select a course';
$string['setting_overwriteconf'] = 'Overwrite course configuration';
$string['setting_course_fullname'] = 'Course name';
$string['setting_course_shortname'] = 'Course short name';
$string['setting_course_startdate'] = 'Course start date';
$string['setting_keep_roles_and_enrolments'] = 'Keep current roles and enrolments';
$string['setting_keep_groups_and_groupings'] = 'Keep current groups and groupings';
$string['setting_overwrite_conf'] = 'Overwrite course configuration';
$string['setting_overwrite_course_fullname'] = 'Overwrite course full name';
$string['setting_overwrite_course_shortname'] = 'Overwrite course short name';
$string['setting_overwrite_course_startdate'] = 'Overwrite course start date';
$string['showtypes'] = 'Show type options';
$string['skiphidden'] = 'Skip hidden courses';
$string['skiphiddenhelp'] = 'Choose whether or not to skip hidden courses';

View File

@ -5125,6 +5125,28 @@ class admin_setting_configselect_with_advanced extends admin_setting_configselec
}
/**
* Select with an advanced checkbox that controls an additional $name.'_locked' config setting.
*
* @copyright 2017 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class admin_setting_configselect_with_lock extends admin_setting_configselect {
/**
* Constructor
* @param string $name unique ascii name, either 'mysetting' for settings that in config,
* or 'myplugin/mysetting' for ones in config_plugins.
* @param string $visiblename localised
* @param string $description long localised info
* @param array $defaultsetting ('value'=>string, 'locked'=>bool)
* @param array $choices array of $value=>$label for each selection
*/
public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices);
$this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked']));
}
}
/**
* Graded roles in gradebook