diff --git a/README.md b/README.md index 703b046..07e36ae 100755 --- a/README.md +++ b/README.md @@ -29,3 +29,37 @@ Any Problems, questions, suggestions If you have a problem with this block, suggestions for improvement, drop an email at : - Pimenko : contact@pimenko.com - Github : https://github.com/DigiDago/moodle-block_admin_presets + +Usage +=================== +- **Check if plugin is installed :** +go to *Admin > Plugins > Plugins overview > Additional Plugins > Admin presets*. It's installed if it appears. +- **Set-up the block :** Make the block appear in your 'Site Home' page by adding it to the page, go to *Site Home > Turn Editing On*. Then go to *Add Block > Admin presets* +- **Usage :** In the 'Site Home' page, an admin_preset block should now appear. from there you can + + - **Import a config file :** Just drag&drop a config_file generated by admin_presets from this moodle or another one. Just in case, before importing anything you should always export your actual configuration to be able to retrieve it later. + - **Export your current config :** Select all the settings you wish to be in your export file, **by default all settings are selected**. Be careful not to select unnecessary settings because the selected settings will always override previous settings at the import. The config.xml file won't be downloaded right away, you will find it in the presets list. + - **See the presets list :** Here are listed all the imported & exported config files, from there you can + - Preview : see the config to check which settings are contained + - Load : load the config onto the site + - Download : download a .xml fil containing the config, allowing you to import it to any moodle project running the admin_presets plugin + - Delete : permanently remove that configuration from de presets list +> Carefull : settings related to the Moodle Theme are exported/imported but the used theme still needs to be set manually. + + +Automatic Export +=================== +A feature was added allowing the plugin to perform an automatic export which will provide a daily back-up if enabled. You can enable this setting the same way you're configuring the plugin following : *Admin > Plugins > Plugins overview > Additional Plugins > Admin presets > Settings*. +These backups are named with a timestamp looking like '20210816160918' and will be found with any other record of admin_presets : in the "presets" list that regroups exports, imports and automatic backups. + +### How it works +- Automatic export daily at 23:00, creates an export with full config named with a time stamp **default : Enabled** +- Automatic export cleanup runs daily at 23:30, will delete automatic exports as follows + - Last 7 weeks : keeps all + - Last 14 days : keeps one export out of 2 + - Last month : keeps one export out of 4 + - Last 3 months : keeps one export out of 8 + - Older than 3 months : deletes all +> This feature only targets automatic exports, if you perform a manual export or import they'll stay untouched. +> +> If you import an automatic export in this project or another, it won't be targeted by this cleanup feature diff --git a/classes/task/automatic_export.php b/classes/task/automatic_export.php new file mode 100644 index 0000000..050af8e --- /dev/null +++ b/classes/task/automatic_export.php @@ -0,0 +1,145 @@ +. + +/** + * @author amayard@cblue.be + * @date 16/08/2021 + * @copyright 2021, CBlue SPRL, support@cblue.be + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package block_admin_presets + */ + +namespace block_admin_presets\task; + +use admin_presets_export; +use coding_exception; +use core\task\scheduled_task; +use dml_exception; +use stdClass; + +defined('MOODLE_INTERNAL') || die(); + +class automatic_export extends scheduled_task { + + /** + * @return string + * @throws coding_exception + */ + public function get_name() { + return get_string('automaticexport', 'block_admin_presets'); + } + + /** + * This function is meant to be called by a CRON task, see the ../db/tasks.php file to check how it is programmed. + * This function will get all site's settings through the _get_setting() function, it'll then will loop through them and construct a $_POST array that'll be handled to create an admin_presets valid database record. The record will be named with a timestamp YearMonthDayHourMinuteSecond. + * If the config is successfully recorded, the function will return true, if not it'll throw the appropriate Exception along the way. + * + * For testing purposes you can manually launch this function : sudo -u www-data php7.3 admin/cli/scheduled_task.php --execute="\block_admin_presets\task\automatic_export" + * + * @return bool + * @throws \moodle_exception + * @throws coding_exception + * @throws dml_exception + */ + public function execute() { + global $CFG, $DB; + + $config = get_config('block_admin_presets', 'automaticexport'); + if (empty($config)) { + return; + } + + require_once $CFG->dirroot . "/blocks/admin_presets/lib/admin_presets_export.class.php"; + + $export = new admin_presets_export(); + + // Reload site settings. + $sitesettings = $export->load_site_settings(); + + //Construct $presets for each site setting + foreach ($sitesettings as $sitesetting => $settingvalue) { + foreach ($settingvalue as $key => $value) { + $presets[$key . '@@' . $sitesetting] = '1'; + } + } + + // admin_preset record. + $preset = new stdClass(); + $preset->userid = '1'; + $preset->name = date('YmdGis'); + $preset->comments = $presets['comments']['text']; + $preset->site = $CFG->wwwroot; + $preset->author = $presets['author']; + $preset->moodleversion = $CFG->version; + $preset->moodlerelease = $CFG->release; + $preset->timecreated = time(); + $preset->timemodified = 0; + if (!$preset->id = $DB->insert_record('block_admin_presets', $preset)) { + print_error('errorinserting', 'block_admin_presets'); + } + + // Store it here for logging and other future id-oriented stuff. + $this->id = $preset->id; + + // We must ensure that there are settings selected. + foreach ($presets as $varname => $value) { + + unset($setting); + + if (strstr($varname, '@@') != false) { + + $settingsfound = true; + + $name = explode('@@', $varname); + $setting = new StdClass(); + $setting->adminpresetid = $preset->id; + $setting->plugin = $name[1]; + $setting->name = $name[0]; + $setting->value = $sitesettings[$setting->plugin][$setting->name]->get_value(); + + if (!$setting->id = $DB->insert_record('block_admin_presets_it', $setting)) { + print_error('errorinserting', 'block_admin_presets'); + } + + // Setting attributes must also be exported. + if ($attributes = $sitesettings[$setting->plugin][$setting->name]->get_attributes_values()) { + foreach ($attributes as $attributename => $value) { + + $attr = new StdClass(); + $attr->itemid = $setting->id; + $attr->name = $attributename; + $attr->value = $value; + + $DB->insert_record('block_admin_presets_it_a', $attr); + } + } + } + } + + // If there are no valid or selected settings we should delete the admin preset record. + if (empty($settingsfound)) { + $DB->delete_records('block_admin_presets', ['id' => $preset->id]); + redirect($CFG->wwwroot . '/blocks/admin_presets/index.php?action=export', + get_string('novalidsettingsselected', 'block_admin_presets'), 4); + } + + + // Trigger the as it is usually triggered after execute finishes. + $export->log(); + + return true; + } +} \ No newline at end of file diff --git a/classes/task/automatic_export_cleanup.php b/classes/task/automatic_export_cleanup.php new file mode 100644 index 0000000..2b679d1 --- /dev/null +++ b/classes/task/automatic_export_cleanup.php @@ -0,0 +1,203 @@ +. + +/** + * @author amayard@cblue.be + * @date 16/08/2021 + * @copyright 2021, CBlue SPRL, support@cblue.be + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package block_admin_presets + */ + +namespace block_admin_presets\task; + +use coding_exception; +use core\task\scheduled_task; +use DateTime; + +defined('MOODLE_INTERNAL') || die(); + +class automatic_export_cleanup extends scheduled_task { + + /** + * @return string + * @throws coding_exception + */ + public function get_name() { + return get_string('automaticexportcleanup', 'block_admin_presets'); + } + + /** + * This function is meant to be called by a CRON task, see the ../db/tasks.php file to check how it is programmed. + * This function will get all records of the admin_presets plugin than will sort them into 4 arrays depending on the time creation of the record. + * Each array will then be processed according to what cleanup we want to do : + * records that are younger than 1 week will stay untouched + * records that are older than a week but younger than 2 weeks will be deleted 1 day out of 2 + * records that are older than two weeks but younger than 1 month will be deleted 3 day out of 4 + * records that are older than 1 month but younger than 3 months will be deleted 3 day out of 4 + * records that are older than 3 months will all be deleted + * + * This function will return true if deletion was successfull. Otherwise it'll trhow the apropriate Exception along the way. + * + * For testing purposes you can manually launch this function : sudo -u www-data php7.3 admin/cli/scheduled_task.php --execute="\block_admin_presets\task\automatic_export_cleanup" + * * + * @return bool|void + * @throws \dml_exception + */ + public function execute() { + global $CFG, $DB; + + $config = get_config('block_admin_presets', 'automaticexportcleanup'); + if (empty($config)) { + return; + } + + //get all admin_presets records from DB + $presets = $DB->get_records('block_admin_presets'); + + //set-up arrays for dispatching presets records + $twoweeks = []; + $onemonth = []; + $threemonths = []; + $older = []; + + foreach ($presets as $preset) { + + // checks name to see if automatic backup + if (preg_match('/^[0-9]{14}$/', $preset->name)) { + // check if record is imported or local and sort records according to their age + if ($preset->timeimported == 0) { //if backup is local, check on creation datetime + if ($preset->timecreated > strtotime('-1 weeks')) { + continue; + } elseif ($preset->timecreated > strtotime('-2 weeks')) { + $twoweeks[] = $preset; + continue; + } elseif ($preset->timecreated > strtotime('-1 months')) { + $onemonth[] = $preset; + continue; + } elseif ($preset->timecreated > strtotime('-3 months')) { + $threemonths[] = $preset; + continue; + } elseif ($preset->timecreated < strtotime('-3 months')) { + $older[] = $preset; + continue; + } + } + } + } + + //loop through each now sorted array to delete unwanted records + $this->delete_all_except_nth(2, $twoweeks); + $this->delete_all_except_nth(4, $onemonth); + $this->delete_all_except_nth(8, $threemonths); + $this->delete_all($older); + + return true; + } + + /** + * This function is used to delete records from the admin_presets plugin + * It is called by the delete_all_but_nth() and delete_all() functions. + * @param $record + * @throws \dml_exception + * @throws \moodle_exception + */ + private function delete($record) { + global $DB; + + if (!$DB->delete_records('block_admin_presets', array('id' => $record->id))) { + print_error('errordeleting', 'block_admin_presets'); + } + + // Getting items ids before deleting to delete item attributes. + $items = $DB->get_records('block_admin_presets_it', array('adminpresetid' => $record->id), 'id'); + foreach ($items as $item) { + $DB->delete_records('block_admin_presets_it_a', array('itemid' => $item->id)); + } + + if (!$DB->delete_records('block_admin_presets_it', array('adminpresetid' => $record->id))) { + print_error('errordeleting', 'block_admin_presets'); + } + + // Deleting the preset applications. + if ($previouslyapplied = $DB->get_records('block_admin_presets_app', + array('adminpresetid' => $record->id), 'id')) { + + foreach ($previouslyapplied as $application) { + + // Deleting items. + if (!$DB->delete_records('block_admin_presets_app_it', + array('adminpresetapplyid' => $application->id))) { + + print_error('errordeleting', 'block_admin_presets'); + } + + // Deleting attributes. + if (!$DB->delete_records('block_admin_presets_app_it_a', + array('adminpresetapplyid' => $application->id))) { + + print_error('errordeleting', 'block_admin_presets'); + } + } + + if (!$DB->delete_records('block_admin_presets_app', + array('adminpresetid' => $record->id))) { + + print_error('errordeleting', 'block_admin_presets'); + } + } + } + + /** + * This function will delete every record except 1 out of nth. + * so if nth = 8, it'll delete 7/8 record + * + * The object parameter should be a collection of record of admin_prestes. You can get such a collenction using : + * $object = $DB->get_records('block_admin_presets'); + * + * @param int $nth + * @param $object + * @throws \dml_exception + * @throws \moodle_exception + */ + private function delete_all_except_nth(int $nth, $object) { + $reference_date = new DateTime("1970-01-01"); + + foreach ($object as $record) { + $recorddate = new DateTime(); + $recorddate->setTimestamp($record->timecreated); + if((date_diff($reference_date, $recorddate, true)->days)%$nth != 0) { + $this->delete($record); + } + } + } + + /** + * This function loops through a collection of admin_presets records to delete each of them. + * You can get such a collenction using : + * $object = $DB->get_records('block_admin_presets'); + * + * @param $object + * @throws \dml_exception + * @throws \moodle_exception + */ + private function delete_all($object) { + foreach ($object as $record) { + $this->delete($record); + } + } + +} \ No newline at end of file diff --git a/db/tasks.php b/db/tasks.php new file mode 100644 index 0000000..6bb8323 --- /dev/null +++ b/db/tasks.php @@ -0,0 +1,44 @@ +. + +/** + * @author amayard@cblue.be + * @date 16/08/2021 + * @copyright 2021, CBlue SPRL, support@cblue.be + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package block_admin_presets + */ + +defined('MOODLE_INTERNAL') || die(); + +$tasks = [ + [ + 'classname' => 'block_admin_presets\task\automatic_export', + 'blocking' => false, + 'minute' => 0, + 'hour' => 23, + 'day' => '*', + 'month' => '*', + ], + [ + 'classname' => 'block_admin_presets\task\automatic_export_cleanup', + 'blocking' => false, + 'minute' => 30, + 'hour' => 23, + 'day' => '*', + 'month' => '*', + ] +]; \ No newline at end of file diff --git a/lang/en/block_admin_presets.php b/lang/en/block_admin_presets.php index 033cec5..3153fd1 100755 --- a/lang/en/block_admin_presets.php +++ b/lang/en/block_admin_presets.php @@ -117,4 +117,11 @@ $string['voidvalue'] = 'that setting does not have a value'; $string['wrongfile'] = 'Wrong file'; $string['wrongid'] = 'Wrong id'; -$string['privacy:null_reason'] = 'The admin presets block does not effect or store any user data'; \ No newline at end of file +$string['privacy:null_reason'] = 'The admin presets block does not effect or store any user data'; +//CBLUE START +$string['automaticexport'] = 'This is an automatic export of this moodle config'; +$string['automaticexportconfig'] = 'Enable daily automatic backup exports'; +$string['automaticexportcleanupconfig'] = 'Enable automatic export cleanup'; +$string['automaticexportcleanupconfigtext'] = 'If enabled, automatic exports younger than a week will be kept, then up to 14 days 1/2 will be saved, up to a month 1/4 will be saved, then up to 3 months 1/8 will be saved. After 3 months all automatic exports will be deleted. Manual exports and imports won\'t be affected by this functionnality.'; +$string['automaticexportcleanup'] = 'Enable automatic export cleanup'; +//CBLUE END diff --git a/lib/admin_presets_base.class.php b/lib/admin_presets_base.class.php index 697a899..b230080 100755 --- a/lib/admin_presets_base.class.php +++ b/lib/admin_presets_base.class.php @@ -48,6 +48,16 @@ class admin_presets_base { protected $moodleform; protected $rel; + /** + * This function will be used to call _get_site_settings with public privileges + * + * @return array + * @throws dml_exception + */ + public function load_site_settings() { + return $this->_get_site_settings(); + } + /** * Loads common class attributes and initializes sensible settings and DB - XML relations */ diff --git a/settings.php b/settings.php index 4a57c38..e0042bf 100755 --- a/settings.php +++ b/settings.php @@ -33,8 +33,25 @@ $sensiblesettingsdefault .= 'smtppass@none, proxypassword@@none, password@@quiz, '; $sensiblesettingsdefault .= 'enrolpassword@@moodlecourse, allowedip@@none, blockedip@@none'; - $settings->add(new admin_setting_configtextarea('admin_presets/sensiblesettings', + $settings->add(new admin_setting_configtextarea('block_admin_presets/sensiblesettings', get_string('sensiblesettings', 'block_admin_presets'), get_string('sensiblesettingstext', 'block_admin_presets'), $sensiblesettingsdefault, PARAM_TEXT)); + + //CBLUE START + $automaticexportdefault = false ; + $automaticexportcleanupdefault = true ; + + $settings->add(new admin_setting_configcheckbox( + 'block_admin_presets/automaticexport', + get_string('automaticexportconfig', 'block_admin_presets'), + get_string('automaticexportconfig', 'block_admin_presets'), + $automaticexportdefault, true, false)); + + $settings->add(new admin_setting_configcheckbox( + 'block_admin_presets/automaticexportcleanup', + get_string('automaticexportcleanupconfig', 'block_admin_presets'), + get_string('automaticexportcleanupconfigtext', 'block_admin_presets'), + $automaticexportcleanupdefault, true, false)); + //CBLUE END } diff --git a/version.php b/version.php index 54cc6df..98939c3 100755 --- a/version.php +++ b/version.php @@ -26,7 +26,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2021052700; +$plugin->version = 2021052706; $plugin->requires = 2016052300; // Requires this Moodle version $plugin->component = 'block_admin_presets'; $plugin->release = '3.4';