MDL-80191 backup: add subsections to backup form
The patch adds two new levels to the backup form structure: subsection (a delegated section which parent is a course module) and subactivity (an activity inside a subsection). Those new elements are displayed as a inner section below the parent activitiy. For now the UI is the same as a regular section but future issues will define how the UX should be. The new two levels have their own classes to represents settings and have extra dependencies.
This commit is contained in:
@@ -38,6 +38,9 @@ abstract class backup_activity_task extends backup_task {
|
||||
|
||||
protected $moduleid;
|
||||
protected $sectionid;
|
||||
|
||||
/** @var stdClass the section object */
|
||||
protected $section;
|
||||
protected $modulename;
|
||||
protected $activityid;
|
||||
protected $contextid;
|
||||
@@ -50,6 +53,7 @@ abstract class backup_activity_task extends backup_task {
|
||||
* @param backup_plan|null $plan the backup plan instance this task is part of
|
||||
*/
|
||||
public function __construct($name, $moduleid, $plan = null) {
|
||||
global $DB;
|
||||
|
||||
// Check moduleid exists
|
||||
if (!$coursemodule = get_coursemodule_from_id(false, $moduleid)) {
|
||||
@@ -65,6 +69,7 @@ abstract class backup_activity_task extends backup_task {
|
||||
$this->modulename = $coursemodule->modname;
|
||||
$this->activityid = $coursemodule->instance;
|
||||
$this->contextid = context_module::instance($this->moduleid)->id;
|
||||
$this->section = $DB->get_record('course_sections', ['id' => $this->sectionid]);
|
||||
|
||||
parent::__construct($name, $plan);
|
||||
}
|
||||
@@ -90,6 +95,16 @@ abstract class backup_activity_task extends backup_task {
|
||||
return $this->modulename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the activity is inside a subsection.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_in_subsection(): bool {
|
||||
return !empty($this->section->component);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return int the id of the activity instance (id in the activity's instances table)
|
||||
*/
|
||||
@@ -291,7 +306,11 @@ abstract class backup_activity_task extends backup_task {
|
||||
* @return section_backup_setting the setting added
|
||||
*/
|
||||
protected function add_section_setting(int|string $identifier, string $type, string|int $value): activity_backup_setting {
|
||||
$setting = new backup_activity_generic_setting($identifier, $type, $value);
|
||||
if ($this->is_in_subsection()) {
|
||||
$setting = new backup_subactivity_generic_setting($identifier, $type, $value);
|
||||
} else {
|
||||
$setting = new backup_activity_generic_setting($identifier, $type, $value);
|
||||
}
|
||||
$this->add_setting($setting);
|
||||
return $setting;
|
||||
}
|
||||
@@ -308,7 +327,11 @@ abstract class backup_activity_task extends backup_task {
|
||||
// - activities root setting.
|
||||
// - sectionincluded setting (if exists).
|
||||
$settingname = $settingprefix . 'included';
|
||||
$activityincluded = new backup_activity_generic_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
if ($this->is_in_subsection()) {
|
||||
$activityincluded = new backup_subactivity_generic_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
} else {
|
||||
$activityincluded = new backup_activity_generic_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
}
|
||||
$activityincluded->get_ui()->set_icon(new image_icon('monologo', get_string('pluginname', $this->modulename),
|
||||
$this->modulename, array('class' => 'iconlarge icon-post ml-1')));
|
||||
$this->add_setting($activityincluded);
|
||||
@@ -342,7 +365,11 @@ abstract class backup_activity_task extends backup_task {
|
||||
// - sectionuserinfo setting (if exists).
|
||||
// - includefield setting.
|
||||
$settingname = $settingprefix . 'userinfo';
|
||||
$activityuserinfo = new backup_activity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
if ($this->is_in_subsection()) {
|
||||
$activityuserinfo = new backup_subactivity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
} else {
|
||||
$activityuserinfo = new backup_activity_userinfo_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
}
|
||||
|
||||
$activityuserinfo->get_ui()->set_label('-');
|
||||
$activityuserinfo->get_ui()->set_visually_hidden_label(
|
||||
|
||||
@@ -202,7 +202,11 @@ class backup_section_task extends backup_task {
|
||||
* @return section_backup_setting the setting added
|
||||
*/
|
||||
protected function add_section_setting(int|string $identifier, string $type, string|int $value): section_backup_setting {
|
||||
$setting = new backup_section_generic_setting($identifier, $type, $value);
|
||||
if ($this->get_delegated_cm()) {
|
||||
$setting = new backup_subsection_generic_setting($identifier, $type, $value);
|
||||
} else {
|
||||
$setting = new backup_section_generic_setting($identifier, $type, $value);
|
||||
}
|
||||
$this->add_setting($setting);
|
||||
return $setting;
|
||||
}
|
||||
@@ -220,9 +224,23 @@ class backup_section_task extends backup_task {
|
||||
// Define sectionincluded (to decide if the whole task must be really executed).
|
||||
$settingname = $settingprefix . 'included';
|
||||
|
||||
$sectionincluded = new backup_section_included_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
$delegatedcmid = $this->get_delegated_cm();
|
||||
if ($delegatedcmid) {
|
||||
$sectionincluded = new backup_subsection_included_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
// Subsections depends on the parent activity included setting.
|
||||
$settingname = $this->get_modname() . '_' . $delegatedcmid . '_included';
|
||||
if ($this->plan->setting_exists($settingname)) {
|
||||
$cmincluded = $this->plan->get_setting($settingname);
|
||||
$cmincluded->add_dependency(
|
||||
$sectionincluded,
|
||||
);
|
||||
}
|
||||
$sectionincluded->get_ui()->set_label(get_string('subsectioncontent', 'backup'));
|
||||
} else {
|
||||
$sectionincluded = new backup_section_included_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
$sectionincluded->get_ui()->set_label(get_section_name($course, $this->section));
|
||||
}
|
||||
|
||||
$sectionincluded->get_ui()->set_label(get_section_name($course, $this->section));
|
||||
$this->add_setting($sectionincluded);
|
||||
|
||||
return $sectionincluded;
|
||||
@@ -244,7 +262,20 @@ class backup_section_task extends backup_task {
|
||||
// - section_included setting.
|
||||
$settingname = $settingprefix . 'userinfo';
|
||||
|
||||
$sectionuserinfo = new backup_section_userinfo_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
$delegatedcmid = $this->get_delegated_cm();
|
||||
if ($delegatedcmid) {
|
||||
$sectionuserinfo = new backup_subsection_userinfo_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
// Subsections depends on the parent activity included setting.
|
||||
$settingname = $this->get_modname() . '_' . $delegatedcmid . '_userinfo';
|
||||
if ($this->plan->setting_exists($settingname)) {
|
||||
$cmincluded = $this->plan->get_setting($settingname);
|
||||
$cmincluded->add_dependency(
|
||||
$sectionuserinfo,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$sectionuserinfo = new backup_section_userinfo_setting($settingname, base_setting::IS_BOOLEAN, true);
|
||||
}
|
||||
|
||||
$sectionuserinfo->get_ui()->set_label(get_string('includeuserinfo', 'backup'));
|
||||
$sectionuserinfo->get_ui()->set_visually_hidden_label(
|
||||
|
||||
@@ -185,6 +185,45 @@ class backup_section_included_setting extends section_backup_setting {}
|
||||
*/
|
||||
class backup_section_userinfo_setting extends section_backup_setting {}
|
||||
|
||||
/**
|
||||
* Subsection base class (section delegated to a course module).
|
||||
*/
|
||||
class subsection_backup_setting extends section_backup_setting {
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param string $name Name of the setting
|
||||
* @param string $vtype Type of the setting, for example base_setting::IS_TEXT
|
||||
* @param mixed $value Value of the setting
|
||||
* @param bool $visibility Is the setting visible in the UI, for example base_setting::VISIBLE
|
||||
* @param int $status Status of the setting with regards to the locking, for example base_setting::NOT_LOCKED
|
||||
*/
|
||||
public function __construct($name, $vtype, $value = null, $visibility = self::VISIBLE, $status = self::NOT_LOCKED) {
|
||||
parent::__construct($name, $vtype, $value, $visibility, $status);
|
||||
$this->level = self::SUBSECTION_LEVEL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* generic section setting to pass various settings between tasks and steps
|
||||
*/
|
||||
class backup_subsection_generic_setting extends subsection_backup_setting {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting to define if one section is included or no. Activities _included
|
||||
* settings depend of them if available
|
||||
*/
|
||||
class backup_subsection_included_setting extends subsection_backup_setting {
|
||||
}
|
||||
|
||||
/**
|
||||
* section backup setting to control if section will include
|
||||
* user information or no, depends of @backup_users_setting
|
||||
*/
|
||||
class backup_subsection_userinfo_setting extends subsection_backup_setting {
|
||||
}
|
||||
|
||||
|
||||
// Activity backup settings
|
||||
|
||||
@@ -206,6 +245,46 @@ class backup_activity_included_setting extends activity_backup_setting {}
|
||||
*/
|
||||
class backup_activity_userinfo_setting extends activity_backup_setting {}
|
||||
|
||||
/**
|
||||
* Subactivity base class (activity inside a delegated section).
|
||||
*/
|
||||
class subactivity_backup_setting extends activity_backup_setting {
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param string $name Name of the setting
|
||||
* @param string $vtype Type of the setting, for example base_setting::IS_TEXT
|
||||
* @param mixed $value Value of the setting
|
||||
* @param bool $visibility Is the setting visible in the UI, for example base_setting::VISIBLE
|
||||
* @param int $status Status of the setting with regards to the locking, for example base_setting::NOT_LOCKED
|
||||
*/
|
||||
public function __construct($name, $vtype, $value = null, $visibility = self::VISIBLE, $status = self::NOT_LOCKED) {
|
||||
parent::__construct($name, $vtype, $value, $visibility, $status);
|
||||
$this->level = self::SUBACTIVITY_LEVEL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic subactivity (activity inside a delegated section) setting to pass various settings between tasks and steps
|
||||
*/
|
||||
class backup_subactivity_generic_setting extends subactivity_backup_setting {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subactivity (activity inside a delegated section) backup setting to control if activity will
|
||||
* be included or no, depends of @backup_activities_setting and
|
||||
* optionally parent section included setting
|
||||
*/
|
||||
class backup_subactivity_included_setting extends subactivity_backup_setting {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subactivity (activity inside a delegated section) backup setting to control if activity will include
|
||||
* user information or no, depends of @backup_users_setting
|
||||
*/
|
||||
class backup_subactivity_userinfo_setting extends subactivity_backup_setting {
|
||||
}
|
||||
|
||||
/**
|
||||
* Root setting to control if backup will include content bank content or no
|
||||
*/
|
||||
|
||||
@@ -246,7 +246,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
continue;
|
||||
}
|
||||
// Validate level is correct (activity)
|
||||
if ($setting->get_level() != backup_setting::ACTIVITY_LEVEL) {
|
||||
if (!in_array($setting->get_level(), [backup_setting::ACTIVITY_LEVEL, backup_setting::SUBACTIVITY_LEVEL])) {
|
||||
throw new backup_controller_exception('setting_not_activity_level', $setting);
|
||||
}
|
||||
$settinginfo = array(
|
||||
@@ -283,7 +283,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
continue;
|
||||
}
|
||||
// Validate level is correct (section)
|
||||
if ($setting->get_level() != backup_setting::SECTION_LEVEL) {
|
||||
if (!in_array($setting->get_level(), [backup_setting::SECTION_LEVEL, backup_setting::SUBSECTION_LEVEL])) {
|
||||
throw new backup_controller_exception('setting_not_section_level', $setting);
|
||||
}
|
||||
$settinginfo = array(
|
||||
|
||||
@@ -37,6 +37,12 @@ abstract class backup_setting extends base_setting implements checksumable {
|
||||
const SECTION_LEVEL = 9;
|
||||
const ACTIVITY_LEVEL = 13;
|
||||
|
||||
/** @var int the subsection level. */
|
||||
const SUBSECTION_LEVEL = 17;
|
||||
|
||||
/** @var int the activity inside a subsection level. */
|
||||
const SUBACTIVITY_LEVEL = 21;
|
||||
|
||||
/** @var int Level of the setting, eg {@link self::ROOT_LEVEL} */
|
||||
protected $level;
|
||||
|
||||
@@ -96,7 +102,12 @@ abstract class backup_setting extends base_setting implements checksumable {
|
||||
}
|
||||
// Check the dependency level is >= current level
|
||||
if ($dependentsetting->get_level() < $this->level) {
|
||||
throw new backup_setting_exception('cannot_add_upper_level_dependency');
|
||||
throw new backup_setting_exception('cannot_add_upper_level_dependency', [
|
||||
$dependentsetting->get_level(),
|
||||
$dependentsetting->get_name(),
|
||||
$this->level,
|
||||
$this->get_name(),
|
||||
]);
|
||||
}
|
||||
parent::add_dependency($dependentsetting, $type, $options);
|
||||
}
|
||||
|
||||
@@ -256,9 +256,11 @@ abstract class backup_setting_ui extends base_setting_ui {
|
||||
$this->name = 'course_'.$setting->get_name();
|
||||
break;
|
||||
case backup_setting::SECTION_LEVEL :
|
||||
case backup_setting::SUBSECTION_LEVEL:
|
||||
$this->name = 'section_'.$setting->get_name();
|
||||
break;
|
||||
case backup_setting::ACTIVITY_LEVEL :
|
||||
case backup_setting::SUBACTIVITY_LEVEL:
|
||||
$this->name = 'activity_'.$setting->get_name();
|
||||
break;
|
||||
}
|
||||
@@ -329,9 +331,10 @@ abstract class backup_setting_ui extends base_setting_ui {
|
||||
// If a task has been provided and the label is not already set meaningfully
|
||||
// we will attempt to improve it.
|
||||
if (!is_null($task) && $this->label == $this->setting->get_name() && strpos($this->setting->get_name(), '_include') !== false) {
|
||||
if ($this->setting->get_level() == backup_setting::SECTION_LEVEL) {
|
||||
$level = $this->setting->get_level();
|
||||
if ($level == backup_setting::SECTION_LEVEL || $level == backup_setting::SUBSECTION_LEVEL) {
|
||||
$this->label = get_string('includesection', 'backup', $task->get_name());
|
||||
} else if ($this->setting->get_level() == backup_setting::ACTIVITY_LEVEL) {
|
||||
} else if ($level == backup_setting::ACTIVITY_LEVEL || $level == backup_setting::SUBACTIVITY_LEVEL) {
|
||||
$this->label = $task->get_name();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,6 +263,16 @@ abstract class base_moodleform extends moodleform {
|
||||
$this->push_group_start('activity', 'grouped_settings activity_level');
|
||||
$this->push_group_start(null, 'include_setting activity_level');
|
||||
break;
|
||||
case backup_setting::SUBSECTION_LEVEL:
|
||||
$this->pop_groups_to('section');
|
||||
$this->push_group_start('subsection', 'grouped_settings subsection_level');
|
||||
$this->push_group_start(null, 'normal_setting');
|
||||
break;
|
||||
case backup_setting::SUBACTIVITY_LEVEL:
|
||||
$this->pop_groups_to('subsection');
|
||||
$this->push_group_start('subactivity', 'grouped_settings activity_level');
|
||||
$this->push_group_start(null, 'include_setting activity_level');
|
||||
break;
|
||||
default:
|
||||
$this->push_group_start(null, 'normal_setting');
|
||||
break;
|
||||
|
||||
@@ -417,6 +417,7 @@ $string['skipmodifdayshelp'] = 'Choose to skip courses that have not been modifi
|
||||
$string['skipmodifprev'] = 'Skip courses not modified since previous backup';
|
||||
$string['skipmodifprevhelp'] = 'Choose whether to skip courses that have not been modified since the last automatic backup. This requires logging to be enabled.';
|
||||
$string['status'] = 'Status';
|
||||
$string['subsectioncontent'] = 'Subsection content';
|
||||
$string['successful'] = 'Backup successful';
|
||||
$string['successfulcopy'] = 'Copy successful';
|
||||
$string['successfulrestore'] = 'Restore successful';
|
||||
|
||||
@@ -12,6 +12,15 @@
|
||||
padding: $card-spacer-x;
|
||||
margin-bottom: $card-spacer-x;
|
||||
}
|
||||
|
||||
&.subsection_level {
|
||||
background-color: $card-bg;
|
||||
@include border-radius($card-border-radius);
|
||||
border: $card-border-width solid $card-border-color;
|
||||
@include clearfix;
|
||||
padding: $card-spacer-x;
|
||||
margin: 0 $card-spacer-x $card-spacer-x $card-spacer-x;
|
||||
}
|
||||
}
|
||||
|
||||
/* These are long labels with checkboxes on the right. */
|
||||
@@ -202,4 +211,3 @@
|
||||
background: $backup-restore-state12-bg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34869,6 +34869,18 @@ img.userpicture {
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
.path-backup .mform .grouped_settings.subsection_level {
|
||||
background-color: #fff;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.125);
|
||||
padding: 1.25rem;
|
||||
margin: 0 1.25rem 1.25rem 1.25rem;
|
||||
}
|
||||
.path-backup .mform .grouped_settings.subsection_level::after {
|
||||
display: block;
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
.path-backup .mform .include_setting {
|
||||
width: 50%;
|
||||
display: inline-block;
|
||||
|
||||
@@ -34869,6 +34869,18 @@ img.userpicture {
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
.path-backup .mform .grouped_settings.subsection_level {
|
||||
background-color: #fff;
|
||||
border-radius: 0.25rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.125);
|
||||
padding: 1.25rem;
|
||||
margin: 0 1.25rem 1.25rem 1.25rem;
|
||||
}
|
||||
.path-backup .mform .grouped_settings.subsection_level::after {
|
||||
display: block;
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
.path-backup .mform .include_setting {
|
||||
width: 50%;
|
||||
display: inline-block;
|
||||
|
||||
Reference in New Issue
Block a user