From f28c0c7245cb4ea3787784582cea667888cf1815 Mon Sep 17 00:00:00 2001 From: Damyon Wiese Date: Tue, 1 Aug 2017 13:18:55 +0800 Subject: [PATCH] MDL-59206 event: Add an event for a config_log This is useful because config_logs are sent via logstores, and we may be interested to know how many people change a particular admin setting across many sites (aggregated data). --- lang/en/moodle.php | 1 + lib/classes/event/config_log_created.php | 118 +++++++++++++++++++++++ lib/datalib.php | 19 +++- lib/tests/admintree_test.php | 37 +++++++ 4 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 lib/classes/event/config_log_created.php diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 6f54a708ae0..8d9e23790bb 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -728,6 +728,7 @@ $string['errorwhenconfirming'] = 'You are not confirmed yet because an error occ $string['eventcommentcreated'] = 'Comment created'; $string['eventcommentdeleted'] = 'Comment deleted'; $string['eventcommentsviewed'] = 'Comments viewed'; +$string['eventconfiglogcreated'] = 'Config log created'; $string['eventcoursecategorycreated'] = 'Category created'; $string['eventcoursecategorydeleted'] = 'Category deleted'; $string['eventcoursecategoryupdated'] = 'Category updated'; diff --git a/lib/classes/event/config_log_created.php b/lib/classes/event/config_log_created.php new file mode 100644 index 00000000000..31366b136be --- /dev/null +++ b/lib/classes/event/config_log_created.php @@ -0,0 +1,118 @@ +. + +/** + * Config log created. + * + * @package core + * @copyright 2017 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace core\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Event class for when an admin config log is created. + * + * @property-read array $other { + * Extra information about event. + * + * - string name: name of config setting + * - string plugin: name of plugin + * - string oldvalue: previous value + * - string value: new value + * } + * + * @package core + * @copyright 2017 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class config_log_created extends base { + + /** + * Initialise required event data properties. + */ + protected function init() { + $this->data['objecttable'] = 'config_log'; + $this->data['crud'] = 'c'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } + + /** + * Returns localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('eventconfiglogcreated'); + } + + /** + * Returns non-localised event description with id's for admin use only. + * + * @return string + */ + public function get_description() { + $name = $this->other['name']; + $plugin = isset($this->other['plugin']) ? $this->other['plugin'] : 'core'; + $value = isset($this->other['value']) ? $this->other['value'] : 'Not set'; + $oldvalue = isset($this->other['oldvalue']) ? $this->other['oldvalue'] : 'Not set'; + return "The user with id '$this->userid' changed the config setting '$name' for component '$plugin' " . + "from '$oldvalue' to '$value'."; + } + + /** + * Returns relevant URL. + * + * @return \moodle_url + */ + public function get_url() { + return new \moodle_url('/admin/index.php'); + } + + /** + * Custom validation. + * + * @throws \coding_exception + * @return void + */ + protected function validate_data() { + parent::validate_data(); + + if (!isset($this->other['name'])) { + throw new \coding_exception('The \'name\' value must be set in other.'); + } + if (!array_key_exists('plugin', $this->other)) { + throw new \coding_exception('The \'plugin\' value must be set in other.'); + } + if (!array_key_exists('oldvalue', $this->other)) { + throw new \coding_exception('The \'oldvalue\' value must be set in other.'); + } + if (!array_key_exists('value', $this->other)) { + throw new \coding_exception('The \'value\' value must be set in other.'); + } + } + + public static function get_objectid_mapping() { + // Config log is not mappable. + return array('db' => 'config_log', 'restore' => base::NOT_MAPPED); + } + + public static function get_other_mapping() { + return false; + } +} diff --git a/lib/datalib.php b/lib/datalib.php index df48d6d8500..96b4dcd4e4a 100644 --- a/lib/datalib.php +++ b/lib/datalib.php @@ -1573,13 +1573,28 @@ function add_to_config_log($name, $oldvalue, $value, $plugin) { global $USER, $DB; $log = new stdClass(); - $log->userid = during_initial_install() ? 0 :$USER->id; // 0 as user id during install + // Use 0 as user id during install. + $log->userid = during_initial_install() ? 0 : $USER->id; $log->timemodified = time(); $log->name = $name; $log->oldvalue = $oldvalue; $log->value = $value; $log->plugin = $plugin; - $DB->insert_record('config_log', $log); + + $id = $DB->insert_record('config_log', $log); + + $event = core\event\config_log_created::create(array( + 'objectid' => $id, + 'userid' => $log->userid, + 'context' => \context_system::instance(), + 'other' => array( + 'name' => $log->name, + 'oldvalue' => $log->oldvalue, + 'value' => $log->value, + 'plugin' => $log->plugin + ) + )); + $event->trigger(); } /** diff --git a/lib/tests/admintree_test.php b/lib/tests/admintree_test.php index f6d581d6afa..5db8d37ccdd 100644 --- a/lib/tests/admintree_test.php +++ b/lib/tests/admintree_test.php @@ -111,6 +111,43 @@ class core_admintree_testcase extends advanced_testcase { $tree->add('root', new admin_category('bar', 'Bar'), ''); } + /** + * Test that changes to config trigger events. + */ + public function test_config_log_created_event() { + global $DB; + $this->resetAfterTest(); + $this->setAdminUser(); + + $adminroot = new admin_root(true); + $adminroot->add('root', $one = new admin_category('one', 'One')); + $page = new admin_settingpage('page', 'Page'); + $page->add(new admin_setting_configtext('text1', 'Text 1', '', '')); + $page->add(new admin_setting_configpasswordunmask('pass1', 'Password 1', '', '')); + $adminroot->add('one', $page); + + $sink = $this->redirectEvents(); + $data = array('s__text1' => 'sometext', 's__pass1' => ''); + $this->save_config_data($adminroot, $data); + + $events = $sink->get_events(); + $sink->close(); + $event = array_pop($events); + $this->assertInstanceOf('\core\event\config_log_created', $event); + + $sink = $this->redirectEvents(); + $data = array('s__text1'=>'other', 's__pass1'=>'nice password'); + $count = $this->save_config_data($adminroot, $data); + + $events = $sink->get_events(); + $sink->close(); + $event = array_pop($events); + $this->assertInstanceOf('\core\event\config_log_created', $event); + // Verify password was nuked. + $this->assertNotEquals($event->other['value'], 'nice password'); + + } + /** * Testing whether a configexecutable setting is executable. */