diff --git a/admin/settings/server.php b/admin/settings/server.php
index 20f69b27e72..ec37e4351a9 100644
--- a/admin/settings/server.php
+++ b/admin/settings/server.php
@@ -137,21 +137,6 @@ $temp->add(new admin_setting_configselect('deleteincompleteusers', new lang_stri
48 => new lang_string('numdays', '', 2),
24 => new lang_string('numdays', '', 1))));
-$temp->add(new admin_setting_configcheckbox('logguests', new lang_string('logguests', 'admin'),
- new lang_string('logguests_help', 'admin'), 1));
-$temp->add(new admin_setting_configselect('loglifetime', new lang_string('loglifetime', 'admin'), new lang_string('configloglifetime', 'admin'), 0, array(0 => new lang_string('neverdeletelogs'),
- 1000 => new lang_string('numdays', '', 1000),
- 365 => new lang_string('numdays', '', 365),
- 180 => new lang_string('numdays', '', 180),
- 150 => new lang_string('numdays', '', 150),
- 120 => new lang_string('numdays', '', 120),
- 90 => new lang_string('numdays', '', 90),
- 60 => new lang_string('numdays', '', 60),
- 35 => new lang_string('numdays', '', 35),
- 10 => new lang_string('numdays', '', 10),
- 5 => new lang_string('numdays', '', 5),
- 2 => new lang_string('numdays', '', 2))));
-
$temp->add(new admin_setting_configcheckbox('disablegradehistory', new lang_string('disablegradehistory', 'grades'),
new lang_string('disablegradehistory_help', 'grades'), 0));
diff --git a/admin/tool/log/classes/log/manager.php b/admin/tool/log/classes/log/manager.php
new file mode 100644
index 00000000000..0697f774991
--- /dev/null
+++ b/admin/tool/log/classes/log/manager.php
@@ -0,0 +1,166 @@
+.
+
+/**
+ * Log store manager.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_log\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+class manager implements \core\log\manager {
+ /** @var \core\log\reader[] $readers list of initialised log readers */
+ protected $readers;
+
+ /** @var \tool_log\log\writer[] $writers list of initialised log writers */
+ protected $writers;
+
+ /** @var \tool_log\log\store[] $stores */
+ protected $stores;
+
+ /**
+ * Delayed initialisation of singleton.
+ */
+ protected function init() {
+ if (isset($this->stores)) {
+ // Do not bother checking readers and writers here
+ // because everything is init here.
+ return;
+ }
+ $this->stores = array();
+ $this->readers = array();
+ $this->writers = array();
+
+ // Register shutdown handler - this may be useful for buffering, file handle closing, etc.
+ \core_shutdown_manager::register_function(array($this, 'dispose'));
+
+ $plugins = get_config('tool_log', 'enabled_stores');
+ if (empty($plugins)) {
+ return;
+ }
+
+ $plugins = explode(',', $plugins);
+ foreach ($plugins as $plugin) {
+ $classname = "\\$plugin\\log\\store";
+ if (class_exists($classname)) {
+ $store = new $classname($this);
+ $this->stores[$plugin] = $store;
+ if ($store instanceof \tool_log\log\writer) {
+ $this->writers[$plugin] = $store;
+ }
+ if ($store instanceof \core\log\reader) {
+ $this->readers[$plugin] = $store;
+ }
+ }
+ }
+ }
+
+ /**
+ * Called from the observer only.
+ *
+ * @param \core\event\base $event
+ */
+ public function process(\core\event\base $event) {
+ $this->init();
+ foreach ($this->writers as $plugin => $writer) {
+ try {
+ $writer->write($event, $this);
+ } catch (\Exception $e) {
+ debugging('Exception detected when logging event '.$event->eventname.' in '.$plugin.': '.$e->getMessage(), DEBUG_NORMAL, $e->getTrace());
+ }
+ }
+ }
+
+ /**
+ * Returns list of available log readers.
+ *
+ * This way the reports find out available sources of data.
+ *
+ * @param \context $context
+ * @return \core\log\reader[] list of available log data readers
+ */
+ public function get_readers(\context $context) {
+ $this->init();
+ $return = array();
+ foreach ($this->readers as $plugin => $reader) {
+ if ($reader->can_access($context)) {
+ $return[$plugin] = $reader;
+ }
+ }
+ return $return;
+ }
+
+ /**
+ * Intended for store management, do not use from reports.
+ *
+ * @return store[] Returns list of available store plugins.
+ */
+ public static function get_store_plugins() {
+ return \core_component::get_plugin_list_with_class('logstore', 'log\store');
+ }
+
+ /**
+ * Usually called automatically from shutdown manager,
+ * this allows us to implement buffering of write operations.
+ */
+ public function dispose() {
+ if ($this->stores) {
+ foreach ($this->stores as $store) {
+ $store->dispose();
+ }
+ }
+ $this->stores = null;
+ $this->readers = null;
+ $this->writers = null;
+ }
+
+ /**
+ * Execute cron actions.
+ */
+ public function cron() {
+ $this->init();
+ foreach ($this->stores['legacy'] as $store) {
+ $store->cron();
+ }
+ }
+
+ /**
+ * Legacy add_to_log() redirection.
+ *
+ * To be used only from deprecated add_to_log() function and event trigger() method.
+ *
+ * NOTE: this is hardcoded to legacy log store plugin, hopefully we can get rid of it soon.
+ *
+ * @param int $courseid The course id
+ * @param string $module The module name e.g. forum, journal, resource, course, user etc
+ * @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify.
+ * @param string $url The file and parameters used to see the results of the action
+ * @param string $info Additional description information
+ * @param int $cm The course_module->id if there is one
+ * @param int|\stdClass $user If log regards $user other than $USER
+ */
+ public function legacy_add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user=0) {
+ $this->init();
+ if (isset($this->stores['legacy'])) {
+ $this->stores['legacy']->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user);
+ }
+ }
+}
diff --git a/admin/tool/log/classes/log/observer.php b/admin/tool/log/classes/log/observer.php
new file mode 100644
index 00000000000..0728937db60
--- /dev/null
+++ b/admin/tool/log/classes/log/observer.php
@@ -0,0 +1,43 @@
+.
+
+/**
+ * Event observer.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_log\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+class observer {
+ /**
+ * Redirect all events to this log manager, but only if this
+ * log manager is actually used.
+ *
+ * @param \core\event\base $event
+ */
+ public static function store(\core\event\base $event) {
+ $logmanager = get_log_manager();
+ if (get_class($logmanager) === 'tool_log\log\manager') {
+ /** @var \tool_log\log\manager $logmanager */
+ $logmanager->process($event);
+ }
+ }
+}
diff --git a/admin/tool/log/classes/log/store.php b/admin/tool/log/classes/log/store.php
new file mode 100644
index 00000000000..1e402655d07
--- /dev/null
+++ b/admin/tool/log/classes/log/store.php
@@ -0,0 +1,49 @@
+.
+
+/**
+ * Log store interface.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_log\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+interface store {
+ /**
+ * Create new instance of store,
+ * the calling code must make sure only one instance exists.
+ *
+ * @param manager $manager
+ */
+ public function __construct(\tool_log\log\manager $manager);
+
+ /**
+ * Notify store no more events are going to be written/read from it.
+ * @return void
+ */
+ public function dispose();
+
+ /**
+ * Execute cron actions.
+ * @return void
+ */
+ public function cron();
+}
diff --git a/admin/tool/log/classes/log/writer.php b/admin/tool/log/classes/log/writer.php
new file mode 100644
index 00000000000..82537ceebde
--- /dev/null
+++ b/admin/tool/log/classes/log/writer.php
@@ -0,0 +1,37 @@
+.
+
+/**
+ * Log store writer interface.
+ *
+ * @package core
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_log\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+interface writer extends store {
+ /**
+ * Write one event to the store.
+ *
+ * @param \core\event\base $event
+ * @return void
+ */
+ public function write(\core\event\base $event);
+}
diff --git a/admin/tool/log/classes/plugininfo/logstore.php b/admin/tool/log/classes/plugininfo/logstore.php
new file mode 100644
index 00000000000..bfd3854809d
--- /dev/null
+++ b/admin/tool/log/classes/plugininfo/logstore.php
@@ -0,0 +1,89 @@
+.
+
+/**
+ * Subplugin info class.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace tool_log\plugininfo;
+
+use core\plugininfo\base, moodle_url, part_of_admin_tree, admin_settingpage;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Plugin info class for logging store plugins.
+ */
+class logstore extends base {
+
+ public function is_enabled() {
+ $enabled = get_config('tool_log', 'enabled_stores');
+ if (!$enabled) {
+ return false;
+ }
+
+ $enabled = array_flip(explode(',', $enabled));
+ return isset($enabled['logstore_'.$this->name]);
+ }
+
+ public function get_settings_section_name() {
+ return 'logsetting' . $this->name;
+ }
+
+ public function load_settings(part_of_admin_tree $adminroot, $parentnodename, $hassiteconfig) {
+ global $CFG, $USER, $DB, $OUTPUT, $PAGE; // In case settings.php wants to refer to them.
+ $ADMIN = $adminroot; // May be used in settings.php.
+ $section = $this->get_settings_section_name();
+
+ if (!$this->is_installed_and_upgraded()) {
+ return;
+ }
+
+ if (!$hassiteconfig or !file_exists($this->full_path('settings.php'))) {
+ return;
+ }
+
+ $settings = new admin_settingpage($section, $this->displayname, 'moodle/site:config', $this->is_enabled() === false);
+ include($this->full_path('settings.php'));
+
+ if ($settings) {
+ $ADMIN->add($parentnodename, $settings);
+ }
+ }
+
+ public static function get_manage_url() {
+ return new moodle_url('/admin/settings.php', array('section'=>'managelogging'));
+ }
+
+ public function is_uninstall_allowed() {
+ return true;
+ }
+
+ public function uninstall_cleanup() {
+ $enabled = get_config('tool_log', 'enabled_stores');
+ if ($enabled) {
+ $enabled = array_flip(explode(',', $enabled));
+ unset($enabled['logstore_'.$this->name]);
+ $enabled = array_flip($enabled);
+ set_config('enabled_stores', implode(',', $enabled), 'tool_log');
+ }
+
+ parent::uninstall_cleanup();
+ }
+}
diff --git a/admin/tool/log/classes/setting_managestores.php b/admin/tool/log/classes/setting_managestores.php
new file mode 100644
index 00000000000..2e9b8e5f519
--- /dev/null
+++ b/admin/tool/log/classes/setting_managestores.php
@@ -0,0 +1,229 @@
+.
+
+/**
+ * Store management setting.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once("$CFG->libdir/adminlib.php");
+
+class tool_log_setting_managestores extends admin_setting {
+ /**
+ * Calls parent::__construct with specific arguments
+ */
+ public function __construct() {
+ $this->nosave = true;
+ parent::__construct('tool_log_manageui', get_string('managelogging', 'tool_log'), '', '');
+ }
+
+ /**
+ * Always returns true, does nothing.
+ *
+ * @return true
+ */
+ public function get_setting() {
+ return true;
+ }
+
+ /**
+ * Always returns true, does nothing.
+ *
+ * @return true
+ */
+ public function get_defaultsetting() {
+ return true;
+ }
+
+ /**
+ * Always returns '', does not write anything.
+ *
+ * @param mixed $data ignored
+ * @return string Always returns ''
+ */
+ public function write_setting($data) {
+ // Do not write any setting.
+ return '';
+ }
+
+ /**
+ * Checks if $query is one of the available log plugins.
+ *
+ * @param string $query The string to search for
+ * @return bool Returns true if found, false if not
+ */
+ public function is_related($query) {
+ if (parent::is_related($query)) {
+ return true;
+ }
+
+ $query = core_text::strtolower($query);
+ $plugins = \tool_log\log\manager::get_store_plugins();
+ foreach ($plugins as $plugin => $fulldir) {
+ if (strpos(core_text::strtolower($plugin), $query) !== false) {
+ return true;
+ }
+ $localised = get_string('pluginname', $plugin);
+ if (strpos(core_text::strtolower($localised), $query) !== false) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Builds the XHTML to display the control.
+ *
+ * @param string $data Unused
+ * @param string $query
+ * @return string
+ */
+ public function output_html($data, $query='') {
+ global $OUTPUT, $PAGE;
+
+ // Display strings.
+ $strup = get_string('up');
+ $strdown = get_string('down');
+ $strsettings = get_string('settings');
+ $strenable = get_string('enable');
+ $strdisable = get_string('disable');
+ $struninstall = get_string('uninstallplugin', 'core_admin');
+ $strversion = get_string('version');
+
+ $pluginmanager = core_plugin_manager::instance();
+
+ $available = \tool_log\log\manager::get_store_plugins();
+ $enabled = get_config('tool_log', 'enabled_stores');
+ if (!$enabled) {
+ $enabled = array();
+ } else {
+ $enabled = array_flip(explode(',', $enabled));
+ }
+
+ $allstores = array();
+ foreach ($enabled as $key => $store) {
+ $allstores[$key] = true;
+ $enabled[$key] = true;
+ }
+ foreach ($available as $key => $store) {
+ $allstores[$key] = true;
+ $available[$key] = true;
+ }
+
+ $return = $OUTPUT->heading(get_string('actlogshdr', 'tool_log'), 3, 'main', true);
+ $return .= $OUTPUT->box_start('generalbox loggingui');
+
+ $table = new html_table();
+ $table->head = array(get_string('name'), $strversion, $strenable, $strup.'/'.$strdown, $strsettings, $struninstall);
+ $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
+ $table->id = 'logstoreplugins';
+ $table->attributes['class'] = 'admintable generaltable';
+ $table->data = array();
+
+ // Iterate through store plugins and add to the display table.
+ $updowncount = 1;
+ $storecount = count($enabled);
+ $url = new moodle_url('/admin/tool/log/stores.php', array('sesskey'=>sesskey()));
+ $printed = array();
+ foreach ($allstores as $store => $unused) {
+ $plugininfo = $pluginmanager->get_plugin_info($store);
+ $version = get_config($store, 'version');
+ if ($version === false) {
+ $version = '';
+ }
+
+ if (get_string_manager()->string_exists('pluginname', $store)) {
+ $name = get_string('pluginname', $store);
+ } else {
+ $name = $store;
+ }
+
+ // Hide/show links.
+ if (isset($enabled[$store])) {
+ $aurl = new moodle_url($url, array('action'=>'disable', 'store'=>$store));
+ $hideshow = "";
+ $hideshow .= "
pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"$strdisable\" />";
+ $isenabled = true;
+ $displayname = "$name";
+ } else if (isset($available[$store])) {
+ $aurl = new moodle_url($url, array('action'=>'enable', 'store'=>$store));
+ $hideshow = "";
+ $hideshow .= "
pix_url('t/show') . "\" class=\"iconsmall\" alt=\"$strenable\" />";
+ $isenabled = false;
+ $displayname = "$name";
+ } else {
+ $hideshow = '';
+ $isenabled = false;
+ $displayname = ''.$name.'';
+ }
+ if ($PAGE->theme->resolve_image_location('icon', $store, false)) {
+ $icon = $OUTPUT->pix_icon('icon', '', $store, array('class' => 'icon pluginicon'));
+ } else {
+ $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
+ }
+
+ // Up/down link (only if store is enabled).
+ $updown = '';
+ if ($isenabled) {
+ if ($updowncount > 1) {
+ $aurl = new moodle_url($url, array('action'=>'up', 'store'=>$store));
+ $updown .= "";
+ $updown .= "
pix_url('t/up') . "\" alt=\"$strup\" class=\"iconsmall\" /> ";
+ } else {
+ $updown .= "
pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" /> ";
+ }
+ if ($updowncount < $storecount) {
+ $aurl = new moodle_url($url, array('action'=>'down', 'store'=>$store));
+ $updown .= "";
+ $updown .= "
pix_url('t/down') . "\" alt=\"$strdown\" class=\"iconsmall\" />";
+ } else {
+ $updown .= "
pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
+ }
+ ++$updowncount;
+ }
+
+ // Add settings link.
+ if (!$version) {
+ $settings = '';
+ } else if ($surl = $plugininfo->get_settings_url()) {
+ $settings = html_writer::link($surl, $strsettings);
+ } else {
+ $settings = '';
+ }
+
+ // Add uninstall info.
+ $uninstall = '';
+ if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url($store, 'manage')) {
+ $uninstall = html_writer::link($uninstallurl, $struninstall);
+ }
+
+ // Add a row to the table.
+ $table->data[] = array($icon.$displayname, $version, $hideshow, $updown, $settings, $uninstall);
+
+ $printed[$store] = true;
+ }
+
+ $return .= html_writer::table($table);
+ $return .= get_string('configlogplugins', 'tool_log').'
'.get_string('tablenosave', 'admin');
+ $return .= $OUTPUT->box_end();
+ return highlight($query, $return);
+ }
+}
diff --git a/admin/tool/log/db/events.php b/admin/tool/log/db/events.php
new file mode 100644
index 00000000000..ceab58ff147
--- /dev/null
+++ b/admin/tool/log/db/events.php
@@ -0,0 +1,35 @@
+.
+
+/**
+ * Event observer.
+ *
+ * @package tool_log
+ * @category event
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$observers = array (
+ array (
+ 'eventname' => '*',
+ 'callback' => '\tool_log\log\observer::store',
+ 'internal' => false, // This means that we get events only after transaction commit.
+ 'priority' => 1000,
+ ),
+);
diff --git a/admin/tool/log/db/install.php b/admin/tool/log/db/install.php
new file mode 100644
index 00000000000..934db5977bf
--- /dev/null
+++ b/admin/tool/log/db/install.php
@@ -0,0 +1,41 @@
+.
+
+/**
+ * Logging support.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+function xmldb_tool_log_install() {
+ global $CFG;
+
+ $enabled = array();
+
+ if (file_exists("$CFG->dirroot/$CFG->admin/tool/log/store/standard")) {
+ $enabled[] = 'logstore_standard';
+ }
+
+ if (file_exists("$CFG->dirroot/$CFG->admin/tool/log/store/legacy")) {
+ $enabled[] = 'logstore_legacy';
+ }
+
+ set_config('enabled_stores', implode(',', $enabled), 'tool_log');
+}
diff --git a/admin/tool/log/db/subplugins.php b/admin/tool/log/db/subplugins.php
new file mode 100644
index 00000000000..4eb8fa6da20
--- /dev/null
+++ b/admin/tool/log/db/subplugins.php
@@ -0,0 +1,24 @@
+.
+
+/**
+ * Logging subplugins.
+ *
+ * @package tool_log
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$subplugins = array('logstore'=>'admin/tool/log/store');
diff --git a/admin/tool/log/lang/en/tool_log.php b/admin/tool/log/lang/en/tool_log.php
new file mode 100644
index 00000000000..7301031633b
--- /dev/null
+++ b/admin/tool/log/lang/en/tool_log.php
@@ -0,0 +1,29 @@
+.
+
+/**
+ * Store management UI lang strings.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['actlogshdr'] = 'Available log stores';
+$string['configlogplugins'] = 'Please enable all required plugins and arrange then in appropriate order.';
+$string['logging'] = 'Logging';
+$string['managelogging'] = 'Manage log stores';
+$string['pluginname'] = 'Log store manager';
diff --git a/admin/tool/log/lib.php b/admin/tool/log/lib.php
new file mode 100644
index 00000000000..32be81b49ca
--- /dev/null
+++ b/admin/tool/log/lib.php
@@ -0,0 +1,37 @@
+.
+
+/**
+ * Log tool API.
+ *
+ * @package tool_log
+ * @copyright 2014 Petr Skoda {@link http://skodak.org/}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+/**
+ * Execute cron actions.
+ */
+function tool_log_cron() {
+ // Execute cron only if this log manager used.
+ $logmanager = get_log_manager();
+ if (get_class($logmanager) === 'tool_log\log\manager') {
+ /** @var \tool_log\log\manager $logmanager */
+ $logmanager->cron();
+ }
+}
diff --git a/admin/tool/log/settings.php b/admin/tool/log/settings.php
new file mode 100644
index 00000000000..27c263e45a8
--- /dev/null
+++ b/admin/tool/log/settings.php
@@ -0,0 +1,38 @@
+.
+
+/**
+ * Logging settings.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org/}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($hassiteconfig) {
+ $ADMIN->add('modules', new admin_category('logging', new lang_string('logging', 'tool_log')));
+
+ $temp = new admin_settingpage('managelogging', new lang_string('managelogging', 'tool_log'));
+ $temp->add(new tool_log_setting_managestores());
+ $ADMIN->add('logging', $temp);
+
+ foreach (core_plugin_manager::instance()->get_plugins_of_type('logstore') as $plugin) {
+ /** @var \tool_log\plugininfo\logstore $plugin */
+ $plugin->load_settings($ADMIN, 'logging', $hassiteconfig);
+ }
+}
diff --git a/admin/tool/log/store/database/classes/log/store.php b/admin/tool/log/store/database/classes/log/store.php
new file mode 100644
index 00000000000..8a4e63389da
--- /dev/null
+++ b/admin/tool/log/store/database/classes/log/store.php
@@ -0,0 +1,114 @@
+.
+
+/**
+ * External database writer.
+ *
+ * @package logstore_database
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace logstore_database\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+class store implements \tool_log\log\writer {
+ /** @var \tool_log\log\manager $manager */
+ protected $manager;
+ /** @var \moodle_database $extdb */
+ protected $extdb;
+
+ public function __construct(\tool_log\log\manager $manager) {
+ $this->manager = $manager;
+ }
+
+ protected function init() {
+ if (isset($this->extdb)) {
+ return !empty($this->extdb);
+ }
+
+ $dbdriver = $this->get_config('dbdriver');
+ if (!$dbdriver) {
+ $this->extdb = false;
+ return false;
+ }
+ list($dbtype, $dblibrary) = explode('/', $dbdriver);
+
+ if (!$db = \moodle_database::get_driver_instance($dbtype, $dblibrary, true)) {
+ debugging("Unknown driver $dblibrary/$dbtype", DEBUG_DEVELOPER);
+ $this->extdb = false;
+ return false;
+ }
+
+ $dboptions = array();
+ $dboptions['dbpersist'] = $this->get_config('dbpersist', '0');
+ $dboptions['dbsocket'] = $this->get_config('dbsocket', '');
+ $dboptions['dbport'] = $this->get_config('dbport', '');
+ $dboptions['dbschema'] = $this->get_config('dbschema', '');
+ $dboptions['dbcollation'] = $this->get_config('dbcollation', '');
+
+ try {
+ $db->connect($this->get_config('dbhost'), $this->get_config('dbuser'), $this->get_config('dbpass'),
+ $this->get_config('dbname'), $this->get_config('dbprefix'), $dboptions);
+ } catch (\moodle_exception $e) {
+ debugging('Cannot connect to external database: '.$e->getMessage(), DEBUG_DEVELOPER);
+ $this->extdb = false;
+ return false;
+ }
+
+ $this->extdb = $db;
+ return true;
+ }
+
+ protected function get_config($name, $default = null) {
+ $value = \get_config('logstore_database', $name);
+ if ($value !== false) {
+ return $value;
+ }
+ return $default;
+ }
+
+ public function write(\core\event\base $event) {
+ if (!$this->init()) {
+ return;
+ }
+
+ if (!$dbtable = $this->get_config('dbtable')) {
+ return;
+ }
+
+ $data = $event->get_data();
+ if (CLI_SCRIPT) {
+ $data['origin'] = 'cli';
+ } else {
+ $data['origin'] = getremoteaddr();
+ }
+ $data['realuserid'] = \core\session\manager::is_loggedinas() ? $_SESSION['USER']->realuser : null;
+
+ $this->extdb->insert_record($dbtable, $data);
+ }
+
+ public function cron() {
+ }
+
+ public function dispose() {
+ if ($this->extdb) {
+ $this->extdb->dispose();
+ }
+ $this->extdb = null;
+ }
+}
diff --git a/admin/tool/log/store/database/lang/en/logstore_database.php b/admin/tool/log/store/database/lang/en/logstore_database.php
new file mode 100644
index 00000000000..7d95b322bee
--- /dev/null
+++ b/admin/tool/log/store/database/lang/en/logstore_database.php
@@ -0,0 +1,26 @@
+.
+
+/**
+ * Log store lang strings.
+ *
+ * @package logstore_database
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['pluginname'] = 'External database log';
+$string['pluginname_desc'] = 'External database log plugin, the data is stored in external database table.';
diff --git a/admin/tool/log/store/database/settings.php b/admin/tool/log/store/database/settings.php
new file mode 100644
index 00000000000..776f456ef76
--- /dev/null
+++ b/admin/tool/log/store/database/settings.php
@@ -0,0 +1,54 @@
+.
+
+/**
+ * External database log store settings.
+ *
+ * @package logstore_database
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+if ($hassiteconfig) {
+ $options = array(
+ '' => get_string('choose'),
+ 'native/mysqli' => moodle_database::get_driver_instance('mysqli', 'native')->get_name(),
+ 'native/mariadb'=> moodle_database::get_driver_instance('mariadb', 'native')->get_name(),
+ 'native/pgsql' => moodle_database::get_driver_instance('pgsql', 'native')->get_name(),
+ 'native/oci' => moodle_database::get_driver_instance('oci', 'native')->get_name(),
+ 'native/sqlsrv' => moodle_database::get_driver_instance('sqlsrv', 'native')->get_name(),
+ 'native/mssql' => moodle_database::get_driver_instance('mssql', 'native')->get_name(),
+ );
+
+ // TODO: Localise these settings.
+
+ $settings->add(new admin_setting_configselect('logstore_database/dbdriver', 'dbdriver', '', '', $options));
+
+ $settings->add(new admin_setting_configtext('logstore_database/dbhost', 'dbhost', '', ''));
+ $settings->add(new admin_setting_configtext('logstore_database/dbuser', 'dbuser', '', ''));
+ $settings->add(new admin_setting_configtext('logstore_database/dbpass', 'dbpass', '', ''));
+ $settings->add(new admin_setting_configtext('logstore_database/dbname', 'dbname', '', ''));
+ $settings->add(new admin_setting_configtext('logstore_database/dbname', 'dbprefix', '', ''));
+
+ $settings->add(new admin_setting_configcheckbox('logstore_database/dbpersist', 'dbpersist', '', '0'));
+ $settings->add(new admin_setting_configtext('logstore_database/dbsocket', 'dbsocket', '', ''));
+ $settings->add(new admin_setting_configtext('logstore_database/dbport', 'dbport', '', ''));
+ $settings->add(new admin_setting_configtext('logstore_database/dbschema', 'dbschema', '', ''));
+ $settings->add(new admin_setting_configtext('logstore_database/dbcollation', 'dbcollation', '', ''));
+
+}
diff --git a/admin/tool/log/store/database/version.php b/admin/tool/log/store/database/version.php
new file mode 100644
index 00000000000..85eb8c22c41
--- /dev/null
+++ b/admin/tool/log/store/database/version.php
@@ -0,0 +1,29 @@
+.
+
+/**
+ * External database log store.
+ *
+ * @package logstore_standard
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version = 2014011300; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2014011000; // Requires this Moodle version.
+$plugin->component = 'logstore_database'; // Full name of the plugin (used for diagnostics).
diff --git a/admin/tool/log/store/legacy/classes/event/legacy_logged.php b/admin/tool/log/store/legacy/classes/event/legacy_logged.php
new file mode 100644
index 00000000000..4a2a10c90f2
--- /dev/null
+++ b/admin/tool/log/store/legacy/classes/event/legacy_logged.php
@@ -0,0 +1,53 @@
+.
+
+namespace logstore_legacy\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Legacy log emulation event class.
+ *
+ * @package core
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+class legacy_logged extends \core\event\base {
+
+ public function init() {
+ throw new \coding_exception('legacy events cannot be triggered');
+ }
+
+ public static function get_name() {
+ return get_string('event_legacy_logged', 'logstore_legacy');
+ }
+
+ public function get_description() {
+ return $this->other['module'].' '.$this->other['action'].' '.$this->other['info'];
+ }
+
+ public function get_url() {
+ global $CFG;
+ require_once("$CFG->dirroot/course/lib.php");
+
+ $url = \make_log_url($this->other['module'], $this->other['url']);
+ if (!$url) {
+ return null;
+ }
+ return new \moodle_url($url);
+ }
+}
diff --git a/admin/tool/log/store/legacy/classes/log/store.php b/admin/tool/log/store/legacy/classes/log/store.php
new file mode 100644
index 00000000000..6b049620d65
--- /dev/null
+++ b/admin/tool/log/store/legacy/classes/log/store.php
@@ -0,0 +1,191 @@
+.
+
+/**
+ * Legacy log reader.
+ *
+ * @package logstore_legacy
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace logstore_legacy\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+class store implements \tool_log\log\store, \core\log\reader {
+ public function __construct(\tool_log\log\manager $manager) {
+ }
+
+ public function get_name() {
+ return get_string('pluginname', 'logstore_legacy');
+ }
+
+ public function get_description() {
+ return get_string('pluginname_desc', 'logstore_legacy');
+ }
+
+ public function can_access(\context $context) {
+ return has_capability('logstore/legacy:read', $context);
+ }
+
+ public function get_events($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
+ global $DB;
+
+ $selectwhere = str_replace('timecreated', 'time', $selectwhere);
+ $sort = str_replace('timecreated', 'time', $sort);
+
+ $events = array();
+
+ try {
+ $records = $DB->get_records_select('log', $selectwhere, $params, $sort, '*', $limitfrom, $limitnum);
+ } catch (\moodle_exception $ex) {
+ debugging("error converting legacy event data", $ex->getMessage().$ex->debuginfo);
+ }
+
+ foreach ($records as $data) {
+ $events[$data->id] = \logstore_legacy\event\legacy_logged::restore_legacy($data);
+ }
+
+ return $events;
+ }
+
+ public function get_events_count($selectwhere, array $params) {
+ global $DB;
+ $selectwhere = str_replace('timecreated', 'time', $selectwhere);
+ try {
+ return $DB->count_records_select('log', $selectwhere, $params);
+ } catch (\moodle_exception $ex) {
+ debugging("error converting legacy event data", $ex->getMessage().$ex->debuginfo);
+ return 0;
+ }
+ }
+
+ public function cron() {
+ global $CFG, $DB;
+
+ // Delete old logs to save space (this might need a timer to slow it down...).
+ if (!empty($CFG->loglifetime)) { // value in days
+ $loglifetime = time(0) - ($CFG->loglifetime * 3600 * 24);
+ $DB->delete_records_select("log", "time < ?", array($loglifetime));
+ mtrace(" Deleted old log records");
+ }
+ }
+
+ public function dispose() {
+ }
+
+ /**
+ * Legacy add_to_log() code.
+ *
+ * @param int $courseid The course id
+ * @param string $module The module name e.g. forum, journal, resource, course, user etc
+ * @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify.
+ * @param string $url The file and parameters used to see the results of the action
+ * @param string $info Additional description information
+ * @param int $cm The course_module->id if there is one
+ * @param int|\stdClass $user If log regards $user other than $USER
+ */
+ public function legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user) {
+ // Note that this function intentionally does not follow the normal Moodle DB access idioms.
+ // This is for a good reason: it is the most frequently used DB update function,
+ // so it has been optimised for speed.
+ global $DB, $CFG, $USER;
+
+ if ($this->legacy_logging_enabled()) {
+ return;
+ }
+
+ if ($cm === '' || is_null($cm)) { // Postgres won't translate empty string to its default.
+ $cm = 0;
+ }
+
+ if ($user) {
+ $userid = $user;
+ } else {
+ if (\core\session\manager::is_loggedinas()) { // Don't log.
+ return;
+ }
+ $userid = empty($USER->id) ? '0' : $USER->id;
+ }
+
+ if (isset($CFG->logguests) and !$CFG->logguests) {
+ if (!$userid or isguestuser($userid)) {
+ return;
+ }
+ }
+
+ $REMOTE_ADDR = getremoteaddr();
+
+ $timenow = time();
+ if (!empty($url)) { // Could break doing html_entity_decode on an empty var.
+ $url = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
+ } else {
+ $url = '';
+ }
+
+ // Restrict length of log lines to the space actually available in the
+ // database so that it doesn't cause a DB error. Log a warning so that
+ // developers can avoid doing things which are likely to cause this on a
+ // routine basis.
+ if(!empty($info) && \core_text::strlen($info)>255) {
+ $info = \core_text::substr($info,0,252).'...';
+ debugging('Warning: logged very long info',DEBUG_DEVELOPER);
+ }
+
+ // If the 100 field size is changed, also need to alter print_log in course/lib.php.
+ if(!empty($url) && \core_text::strlen($url)>100) {
+ $url = \core_text::substr($url,0,97).'...';
+ debugging('Warning: logged very long URL',DEBUG_DEVELOPER);
+ }
+
+ if (defined('MDL_PERFDB')) { global $PERF ; $PERF->logwrites++;};
+
+ $log = array('time'=>$timenow, 'userid'=>$userid, 'course'=>$courseid, 'ip'=>$REMOTE_ADDR, 'module'=>$module,
+ 'cmid'=>$cm, 'action'=>$action, 'url'=>$url, 'info'=>$info);
+
+ try {
+ $DB->insert_record_raw('log', $log, false);
+ } catch (\dml_exception $e) {
+ debugging('Error: Could not insert a new entry to the Moodle log. '. $e->error, DEBUG_ALL);
+
+ // MDL-11893, alert $CFG->supportemail if insert into log failed.
+ if ($CFG->supportemail and empty($CFG->noemailever)) {
+ // Function email_to_user is not usable because email_to_user tries to write to the logs table,
+ // and this will get caught in an infinite loop, if disk is full.
+ $site = get_site();
+ $subject = 'Insert into log failed at your moodle site '.$site->fullname;
+ $message = "Insert into log table failed at ". date('l dS \of F Y h:i:s A') .".\n It is possible that your disk is full.\n\n";
+ $message .= "The failed query parameters are:\n\n" . var_export($log, true);
+
+ $lasttime = get_config('admin', 'lastloginserterrormail');
+ if(empty($lasttime) || time() - $lasttime > 60*60*24) { // limit to 1 email per day
+ // Using email directly rather than messaging as they may not be able to log in to access a message.
+ mail($CFG->supportemail, $subject, $message);
+ set_config('lastloginserterrormail', time(), 'admin');
+ }
+ }
+ }
+ }
+
+ /**
+ * Did admin request to keep adding new data to legacy log table?
+ * @return bool
+ */
+ protected function legacy_logging_enabled() {
+ return (bool)get_config('logstore_legacy', 'loglegacy');
+ }
+}
diff --git a/admin/tool/log/store/legacy/db/access.php b/admin/tool/log/store/legacy/db/access.php
new file mode 100644
index 00000000000..713e828ba6a
--- /dev/null
+++ b/admin/tool/log/store/legacy/db/access.php
@@ -0,0 +1,38 @@
+.
+
+/**
+ * Defines the capabilities used by standard log store.
+ *
+ * @package logstore_legacy
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+ 'logstore/legacy:read' => array(
+ 'riskbitmask' => RISK_PERSONAL,
+ 'captype' => 'read',
+ 'contextlevel' => CONTEXT_MODULE,
+ 'archetypes' => array(
+ 'manager' => CAP_ALLOW,
+ 'editingteacher' => CAP_ALLOW,
+ 'teacher' => CAP_ALLOW,
+ ),
+ ),
+);
diff --git a/admin/tool/log/store/legacy/lang/en/logstore_legacy.php b/admin/tool/log/store/legacy/lang/en/logstore_legacy.php
new file mode 100644
index 00000000000..391eeb444c9
--- /dev/null
+++ b/admin/tool/log/store/legacy/lang/en/logstore_legacy.php
@@ -0,0 +1,30 @@
+.
+
+/**
+ * Legacy log reader lang strings.
+ *
+ * @package logstore_legacy
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['event_legacy_logged'] = 'Legacy event';
+$string['legacy:read'] = 'Read logs';
+$string['loglegacy'] = 'Log legacy data';
+$string['loglegacy_help'] = 'Add new records to the legacy log table. It is recommended to disable this for performance reasons.';
+$string['pluginname'] = 'Legacy log';
+$string['pluginname_desc'] = 'Legacy log plugin, it can be used for reading of legacy log data stored in mdl_log table.';
diff --git a/admin/tool/log/store/legacy/settings.php b/admin/tool/log/store/legacy/settings.php
new file mode 100644
index 00000000000..6b385616ab3
--- /dev/null
+++ b/admin/tool/log/store/legacy/settings.php
@@ -0,0 +1,52 @@
+.
+
+/**
+ * Legacy logging settings.
+ *
+ * @package logstore_legacy
+ * @copyright 2014 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+if ($hassiteconfig) {
+ $settings->add(new admin_setting_configcheckbox('logstore_legacy/loglegacy',
+ new lang_string('loglegacy', 'logstore_legacy'),
+ new lang_string('loglegacy_help', 'logstore_legacy'), 0));
+
+ $settings->add(new admin_setting_configcheckbox('logguests',
+ new lang_string('logguests', 'admin'),
+ new lang_string('logguests_help', 'admin'), 1));
+
+ $options = array(0 => new lang_string('neverdeletelogs'),
+ 1000 => new lang_string('numdays', '', 1000),
+ 365 => new lang_string('numdays', '', 365),
+ 180 => new lang_string('numdays', '', 180),
+ 150 => new lang_string('numdays', '', 150),
+ 120 => new lang_string('numdays', '', 120),
+ 90 => new lang_string('numdays', '', 90),
+ 60 => new lang_string('numdays', '', 60),
+ 35 => new lang_string('numdays', '', 35),
+ 10 => new lang_string('numdays', '', 10),
+ 5 => new lang_string('numdays', '', 5),
+ 2 => new lang_string('numdays', '', 2));
+
+ $settings->add(new admin_setting_configselect('loglifetime',
+ new lang_string('loglifetime', 'admin'),
+ new lang_string('configloglifetime', 'admin'), 0, $options));
+}
diff --git a/admin/tool/log/store/legacy/version.php b/admin/tool/log/store/legacy/version.php
new file mode 100644
index 00000000000..a10af9ff2a3
--- /dev/null
+++ b/admin/tool/log/store/legacy/version.php
@@ -0,0 +1,29 @@
+.
+
+/**
+ * Legacy log reader.
+ *
+ * @package logstore_legacy
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version = 2014011300; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2014011000; // Requires this Moodle version.
+$plugin->component = 'logstore_legacy'; // Full name of the plugin (used for diagnostics).
diff --git a/admin/tool/log/store/standard/classes/log/store.php b/admin/tool/log/store/standard/classes/log/store.php
new file mode 100644
index 00000000000..481060c01df
--- /dev/null
+++ b/admin/tool/log/store/standard/classes/log/store.php
@@ -0,0 +1,114 @@
+.
+
+/**
+ * Standard log reader/writer.
+ *
+ * @package logstore_standard
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace logstore_standard\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+class store implements \tool_log\log\writer, \core\log\sql_reader {
+ /** @var string $logguests true if logging guest access */
+ protected $logguests;
+
+ public function __construct(\tool_log\log\manager $manager) {
+ $this->logguests = get_config('logstore_standard', 'logguests');
+ if ($this->logguests === false) {
+ // Log everything before setting is saved for the first time.
+ $this->logguests = '1';
+ }
+ }
+
+ public function write(\core\event\base $event) {
+ global $DB;
+
+ // Filter events.
+ if (!CLI_SCRIPT and !$this->logguests) {
+ // Always log inside CLI scripts because we do not login there.
+ if (!isloggedin() or isguestuser()) {
+ return;
+ }
+ }
+
+ $data = $event->get_data();
+ $data['other'] = serialize($data['other']);
+ if (CLI_SCRIPT) {
+ $data['origin'] = 'cli';
+ } else {
+ $data['origin'] = getremoteaddr();
+ }
+ $data['realuserid'] = \core\session\manager::is_loggedinas() ? $_SESSION['USER']->realuser : null;
+
+ $DB->insert_record('logstore_standard_log', $data);
+ }
+
+ public function get_name() {
+ return get_string('pluginname', 'logstore_standard');
+ }
+
+ public function get_description() {
+ return get_string('pluginname_desc', 'logstore_standard');
+ }
+
+ public function can_access(\context $context) {
+ return has_capability('logstore/standard:read', $context);
+ }
+
+ public function get_events($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
+ global $DB;
+
+ $events = array();
+ $records = $DB->get_records_select('logstore_standard_log', $selectwhere, $params, $sort, '*', $limitfrom, $limitnum);
+
+ foreach ($records as $data) {
+ $extra = array('origin'=>$data->origin, 'realuserid'=>$data->realuserid);
+ $data = (array)$data;
+ $id = $data['id'];
+ $data['other'] = unserialize($data['other']);
+ if ($data['other'] === false) {
+ $data['other'] = array();
+ }
+ unset($data['origin']);
+ unset($data['realuserid']);
+ unset($data['id']);
+
+ $events[$id] = \core\event\base::restore($data, $extra);
+ }
+
+ return $events;
+ }
+
+ public function get_events_count($selectwhere, array $params) {
+ global $DB;
+ return $DB->count_records_select('logstore_standard_log', $selectwhere, $params);
+ }
+
+ public function get_log_table() {
+ return 'logstore_standard_log';
+ }
+
+ public function cron() {
+ }
+
+ public function dispose() {
+ }
+}
diff --git a/admin/tool/log/store/standard/db/access.php b/admin/tool/log/store/standard/db/access.php
new file mode 100644
index 00000000000..81e64e5ae4e
--- /dev/null
+++ b/admin/tool/log/store/standard/db/access.php
@@ -0,0 +1,38 @@
+.
+
+/**
+ * Defines the capabilities used by standard log store.
+ *
+ * @package logstore_standard
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+ 'logstore/standard:read' => array(
+ 'riskbitmask' => RISK_PERSONAL,
+ 'captype' => 'read',
+ 'contextlevel' => CONTEXT_MODULE,
+ 'archetypes' => array(
+ 'manager' => CAP_ALLOW,
+ 'editingteacher' => CAP_ALLOW,
+ 'teacher' => CAP_ALLOW,
+ ),
+ ),
+);
diff --git a/admin/tool/log/store/standard/db/install.xml b/admin/tool/log/store/standard/db/install.xml
new file mode 100644
index 00000000000..dddadb382bd
--- /dev/null
+++ b/admin/tool/log/store/standard/db/install.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/admin/tool/log/store/standard/lang/en/logstore_standard.php b/admin/tool/log/store/standard/lang/en/logstore_standard.php
new file mode 100644
index 00000000000..9cd59c18f67
--- /dev/null
+++ b/admin/tool/log/store/standard/lang/en/logstore_standard.php
@@ -0,0 +1,27 @@
+.
+
+/**
+ * Log store lang strings.
+ *
+ * @package logstore_standard
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['pluginname'] = 'Standard log';
+$string['pluginname_desc'] = 'Standard log plugin, the data is stored in Moodle database table.';
+$string['standard:read'] = 'Read logs';
diff --git a/admin/tool/log/store/standard/settings.php b/admin/tool/log/store/standard/settings.php
new file mode 100644
index 00000000000..fae162cd5cd
--- /dev/null
+++ b/admin/tool/log/store/standard/settings.php
@@ -0,0 +1,32 @@
+.
+
+/**
+ * Standard log store settings.
+ *
+ * @package logstore_standard
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+if ($hassiteconfig) {
+
+ // TODO: Localise these settings.
+
+ $settings->add(new admin_setting_configcheckbox('logstore_standard/logguests', 'Log guest actions', '', '1'));
+}
diff --git a/admin/tool/log/store/standard/version.php b/admin/tool/log/store/standard/version.php
new file mode 100644
index 00000000000..9ef5f966600
--- /dev/null
+++ b/admin/tool/log/store/standard/version.php
@@ -0,0 +1,29 @@
+.
+
+/**
+ * Standard log store.
+ *
+ * @package logstore_standard
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version = 2014011300; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2014011000; // Requires this Moodle version.
+$plugin->component = 'logstore_standard'; // Full name of the plugin (used for diagnostics).
diff --git a/admin/tool/log/stores.php b/admin/tool/log/stores.php
new file mode 100644
index 00000000000..9f24cd49b81
--- /dev/null
+++ b/admin/tool/log/stores.php
@@ -0,0 +1,98 @@
+.
+
+/**
+ * Logging store management.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once('../../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+
+$action = required_param('action', PARAM_ALPHANUMEXT);
+$enrol = required_param('store', PARAM_PLUGIN);
+
+$PAGE->set_url('/admin/tool/log/stores.php');
+$PAGE->set_context(context_system::instance());
+
+require_login();
+require_capability('moodle/site:config', context_system::instance());
+require_sesskey();
+
+$all = \tool_log\log\manager::get_store_plugins();
+$enabled = get_config('tool_log', 'enabled_stores');
+if (!$enabled) {
+ $enabled = array();
+} else {
+ $enabled = array_flip(explode(',', $enabled));
+}
+
+$return = new moodle_url('/admin/settings.php', array('section'=>'managelogging'));
+
+$syscontext = context_system::instance();
+
+switch ($action) {
+ case 'disable':
+ unset($enabled[$enrol]);
+ set_config('enabled_stores', implode(',', array_keys($enabled)), 'tool_log');
+ break;
+
+ case 'enable':
+ if (!isset($all[$enrol])) {
+ break;
+ }
+ $enabled = array_keys($enabled);
+ $enabled[] = $enrol;
+ set_config('enabled_stores', implode(',', $enabled), 'tool_log');
+ break;
+
+ case 'up':
+ if (!isset($enabled[$enrol])) {
+ break;
+ }
+ $enabled = array_keys($enabled);
+ $enabled = array_flip($enabled);
+ $current = $enabled[$enrol];
+ if ($current == 0) {
+ break; // Already at the top.
+ }
+ $enabled = array_flip($enabled);
+ $enabled[$current] = $enabled[$current - 1];
+ $enabled[$current - 1] = $enrol;
+ set_config('enabled_stores', implode(',', $enabled), 'tool_log');
+ break;
+
+ case 'down':
+ if (!isset($enabled[$enrol])) {
+ break;
+ }
+ $enabled = array_keys($enabled);
+ $enabled = array_flip($enabled);
+ $current = $enabled[$enrol];
+ if ($current == count($enabled) - 1) {
+ break; // Already at the end.
+ }
+ $enabled = array_flip($enabled);
+ $enabled[$current] = $enabled[$current + 1];
+ $enabled[$current + 1] = $enrol;
+ set_config('enabled_stores', implode(',', $enabled), 'tool_log');
+ break;
+}
+
+redirect($return);
diff --git a/admin/tool/log/version.php b/admin/tool/log/version.php
new file mode 100644
index 00000000000..d72972b86bc
--- /dev/null
+++ b/admin/tool/log/version.php
@@ -0,0 +1,29 @@
+.
+
+/**
+ * Default log manager.
+ *
+ * @package tool_log
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$plugin->version = 2014011300; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2014011000; // Requires this Moodle version.
+$plugin->component = 'tool_log'; // Full name of the plugin (used for diagnostics).
diff --git a/lang/en/admin.php b/lang/en/admin.php
index 2db067d8918..4dda3090b78 100644
--- a/lang/en/admin.php
+++ b/lang/en/admin.php
@@ -1007,7 +1007,6 @@ $string['taskcontextcleanup'] = 'Cleanup contexts';
$string['taskcreatecontexts'] = 'Create missing contexts';
$string['taskdeletecachetext'] = 'Delete old text cache records';
$string['taskdeleteincompleteusers'] = 'Delete incomplete users';
-$string['taskdeletelogs'] = 'Delete logs';
$string['taskdeleteunconfirmedusers'] = 'Delete unconfirmed users';
$string['taskeventscron'] = 'Background processing for events';
$string['taskfiletrashcleanup'] = 'Cleanup files in trash';
diff --git a/lib/classes/event/base.php b/lib/classes/event/base.php
index 38a999e53ea..4795ffa2cee 100644
--- a/lib/classes/event/base.php
+++ b/lib/classes/event/base.php
@@ -347,6 +347,83 @@ abstract class base implements \IteratorAggregate {
return $event;
}
+ /**
+ * Create fake event from legacy log data.
+ *
+ * @param stdClass $legacy
+ * @return base
+ */
+ public static final function restore_legacy($legacy) {
+ $classname = get_called_class();
+ $event = new $classname();
+ $event->restored = true;
+ $event->triggered = true;
+ $event->dispatched = true;
+
+ $context = false;
+ $component = 'legacy';
+ if ($legacy->cmid) {
+ $context = \context_module::instance($legacy->cmid, IGNORE_MISSING);
+ $component = 'mod_'.$legacy->module;
+ } else if ($legacy->course) {
+ $context = \context_course::instance($legacy->course, IGNORE_MISSING);
+ }
+ if (!$context) {
+ $context = \context_system::instance();
+ }
+
+ $event->data = array();
+
+ $event->data['eventname'] = $legacy->module.'_'.$legacy->action;
+ $event->data['component'] = $component;
+ $event->data['action'] = $legacy->action;
+ $event->data['target'] = null;
+ $event->data['objecttable'] = null;
+ $event->data['objectid'] = null;
+ if (strpos($legacy->action, 'view') !== false) {
+ $event->data['crud'] = 'r';
+ } else if (strpos($legacy->action, 'print') !== false) {
+ $event->data['crud'] = 'r';
+ } else if (strpos($legacy->action, 'update') !== false) {
+ $event->data['crud'] = 'u';
+ } else if (strpos($legacy->action, 'hide') !== false) {
+ $event->data['crud'] = 'u';
+ } else if (strpos($legacy->action, 'move') !== false) {
+ $event->data['crud'] = 'u';
+ } else if (strpos($legacy->action, 'write') !== false) {
+ $event->data['crud'] = 'u';
+ } else if (strpos($legacy->action, 'tag') !== false) {
+ $event->data['crud'] = 'u';
+ } else if (strpos($legacy->action, 'remove') !== false) {
+ $event->data['crud'] = 'u';
+ } else if (strpos($legacy->action, 'delete') !== false) {
+ $event->data['crud'] = 'p';
+ } else if (strpos($legacy->action, 'create') !== false) {
+ $event->data['crud'] = 'c';
+ } else if (strpos($legacy->action, 'post') !== false) {
+ $event->data['crud'] = 'c';
+ } else if (strpos($legacy->action, 'add') !== false) {
+ $event->data['crud'] = 'c';
+ } else {
+ // End of guessing...
+ $event->data['crud'] = 'r';
+ }
+ $event->data['edulevel'] = $event::LEVEL_OTHER;
+ $event->data['contextid'] = $context->id;
+ $event->data['contextlevel'] = $context->contextlevel;
+ $event->data['contextinstanceid'] = $context->instanceid;
+ $event->data['userid'] = ($legacy->userid ? $legacy->userid : null);
+ $event->data['courseid'] = ($legacy->course ? $legacy->course : null);
+ $event->data['relateduserid'] = ($legacy->userid ? $legacy->userid : null);
+ $event->data['timecreated'] = $legacy->time;
+
+ $event->logextra = array('origin'=>$legacy->ip, 'realuserid'=>null);
+
+ $event->data['other'] = (array)$legacy;
+
+ return $event;
+ }
+
/**
* Returns event context.
* @return \context
@@ -504,7 +581,10 @@ abstract class base implements \IteratorAggregate {
if (isset($CFG->loglifetime) and $CFG->loglifetime != -1) {
if ($data = $this->get_legacy_logdata()) {
- call_user_func_array('add_to_log', $data);
+ $manager = get_log_manager();
+ if (method_exists($manager, 'legacy_add_to_log')) {
+ call_user_func_array(array($manager, 'legacy_add_to_log'), $data);
+ }
}
}
diff --git a/lib/classes/log/dummy_manager.php b/lib/classes/log/dummy_manager.php
new file mode 100644
index 00000000000..6ca9ecf4b50
--- /dev/null
+++ b/lib/classes/log/dummy_manager.php
@@ -0,0 +1,36 @@
+.
+
+/**
+ * Dummy storage manager, returns nothing.
+ * used when no other manager available.
+ *
+ * @package core
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+class dummy_manager implements manager {
+ public function get_readers(\context $context) {
+ return array();
+ }
+ public function dispose() {
+ }
+}
diff --git a/lib/classes/task/delete_logs_task.php b/lib/classes/log/manager.php
similarity index 50%
rename from lib/classes/task/delete_logs_task.php
rename to lib/classes/log/manager.php
index d25104eace6..1c40f92981d 100644
--- a/lib/classes/task/delete_logs_task.php
+++ b/lib/classes/log/manager.php
@@ -15,44 +15,38 @@
// along with Moodle. If not, see .
/**
- * A scheduled task.
+ * Log storage manager interface.
*
* @package core
- * @copyright 2013 onwards Martin Dougiamas http://dougiamas.com
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-namespace core\task;
+
+namespace core\log;
+
+defined('MOODLE_INTERNAL') || die();
/**
- * Simple task to delete old log records.
+ * Interface describing log readers.
+ *
+ * This is intended for reports, use get_log_manager() to get
+ * the configured instance.
+ *
+ * @package core\log
*/
-class delete_logs_task extends scheduled_task {
-
+interface manager {
/**
- * Get a descriptive name for this task (shown to admins).
+ * Return list of available log readers in given
+ * context for current user.
*
- * @return string
+ * @param \context $context
+ * @return \core\log\reader[]
*/
- public function get_name() {
- return get_string('taskdeletelogs', 'admin');
- }
+ public function get_readers(\context $context);
/**
- * Do the job.
- * Throw exceptions on errors (the job will be retried).
+ * Dispose all initialised stores.
+ * @return void
*/
- public function execute() {
- global $CFG, $DB;
-
- $timenow = time();
-
- // Delete old logs to save space.
- // Value in days.
- if (!empty($CFG->loglifetime)) {
- $loglifetime = $timenow - ($CFG->loglifetime * 3600 * 24);
- $DB->delete_records_select("log", "time < ?", array($loglifetime));
- }
-
- }
-
+ public function dispose();
}
diff --git a/lib/classes/log/reader.php b/lib/classes/log/reader.php
new file mode 100644
index 00000000000..84782259178
--- /dev/null
+++ b/lib/classes/log/reader.php
@@ -0,0 +1,72 @@
+.
+
+/**
+ * Log storage reader interface.
+ *
+ * @package core
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+interface reader {
+ /**
+ * Localised name of the reader.
+ *
+ * To be used in selection for in reports.
+ *
+ * @return string
+ */
+ public function get_name();
+
+ /**
+ * Longer description of the log data source.
+ * @return string
+ */
+ public function get_description();
+
+ /**
+ * Can the current user access this store?
+ * @param \context $context
+ * @return bool
+ */
+ public function can_access(\context $context);
+
+ /**
+ * Fetch records using given criteria.
+ *
+ * @param string $selectwhere
+ * @param array $params
+ * @param string $sort
+ * @param int $limitfrom
+ * @param int $limitnum
+ * @return \core\event\base[]
+ */
+ public function get_events($selectwhere, array $params, $sort, $limitfrom, $limitnum);
+
+ /**
+ * Return number of events matching given criteria.
+ *
+ * @param string $selectwhere
+ * @param array $params
+ * @return int
+ */
+ public function get_events_count($selectwhere, array $params);
+}
diff --git a/lib/classes/log/sql_reader.php b/lib/classes/log/sql_reader.php
new file mode 100644
index 00000000000..d2c5bafc149
--- /dev/null
+++ b/lib/classes/log/sql_reader.php
@@ -0,0 +1,43 @@
+.
+
+/**
+ * Log storage sql reader interface.
+ *
+ * @package core
+ * @copyright 2013 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\log;
+
+defined('MOODLE_INTERNAL') || die();
+
+interface sql_reader extends reader {
+
+ /**
+ * Returns name of the table or database view that
+ * holds the log data in standardised format.
+ *
+ * Note: this table must be used for reading only,
+ * it is strongly recommended to use this in complex reports only.
+ *
+ * TODO: define the standard log columns - watch out for "level" reserved word!
+ *
+ * @return string
+ */
+ public function get_log_table();
+}
diff --git a/lib/classes/plugin_manager.php b/lib/classes/plugin_manager.php
index 167c5444396..802642c85d2 100644
--- a/lib/classes/plugin_manager.php
+++ b/lib/classes/plugin_manager.php
@@ -1028,6 +1028,10 @@ class core_plugin_manager {
'local' => array(
),
+ 'logstore' => array(
+ 'database', 'legacy', 'standard',
+ ),
+
'message' => array(
'email', 'jabber', 'popup'
),
@@ -1117,7 +1121,7 @@ class core_plugin_manager {
'tool' => array(
'assignmentupgrade', 'behat', 'capability', 'customlang',
'dbtransfer', 'generator', 'health', 'innodb', 'installaddon',
- 'langimport', 'multilangupgrade', 'phpunit', 'profiling',
+ 'langimport', 'log', 'multilangupgrade', 'phpunit', 'profiling',
'qeupgradehelper', 'replace', 'spamcleaner', 'task', 'timezoneimport',
'unittest', 'uploadcourse', 'uploaduser', 'unsuproles', 'xmldb'
),
diff --git a/lib/datalib.php b/lib/datalib.php
index a9a44da8083..b3e27769e1e 100644
--- a/lib/datalib.php
+++ b/lib/datalib.php
@@ -1583,6 +1583,41 @@ function coursemodule_visible_for_user($cm, $userid=0) {
/// LOG FUNCTIONS /////////////////////////////////////////////////////
+/**
+ * Get instance of log manager.
+ *
+ * @param bool $forcereload
+ * @return \core\log\manager
+ */
+function get_log_manager($forcereload = false) {
+ /** @var \core\log\manager $singleton */
+ static $singleton = null;
+
+ if ($forcereload and isset($singleton)) {
+ $singleton->dispose();
+ $singleton = null;
+ }
+
+ if (isset($singleton)) {
+ return $singleton;
+ }
+
+ $classname = '\tool_log\log\manager';
+ if (defined('LOG_MANAGER_CLASS')) {
+ $classname = LOG_MANAGER_CLASS;
+ }
+
+ if (!class_exists($classname)) {
+ if (!empty($classname)) {
+ debugging("Cannot find log manager class '$classname'.", DEBUG_DEVELOPER);
+ }
+ $classname = '\core\log\dummy_manager';
+ }
+
+ $singleton = new $classname();
+ return $singleton;
+}
+
/**
* Add an entry to the config log table.
*
@@ -1613,109 +1648,6 @@ function add_to_config_log($name, $oldvalue, $value, $plugin) {
$DB->insert_record('config_log', $log);
}
-/**
- * Add an entry to the log table.
- *
- * Add an entry to the log table. These are "action" focussed rather
- * than web server hits, and provide a way to easily reconstruct what
- * any particular student has been doing.
- *
- * @package core
- * @category log
- * @global moodle_database $DB
- * @global stdClass $CFG
- * @global stdClass $USER
- * @uses SITEID
- * @uses DEBUG_DEVELOPER
- * @uses DEBUG_ALL
- * @param int $courseid The course id
- * @param string $module The module name e.g. forum, journal, resource, course, user etc
- * @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify.
- * @param string $url The file and parameters used to see the results of the action
- * @param string $info Additional description information
- * @param string $cm The course_module->id if there is one
- * @param string $user If log regards $user other than $USER
- * @return void
- */
-function add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user=0) {
- // Note that this function intentionally does not follow the normal Moodle DB access idioms.
- // This is for a good reason: it is the most frequently used DB update function,
- // so it has been optimised for speed.
- global $DB, $CFG, $USER;
-
- if ($cm === '' || is_null($cm)) { // postgres won't translate empty string to its default
- $cm = 0;
- }
-
- if ($user) {
- $userid = $user;
- } else {
- if (\core\session\manager::is_loggedinas()) { // Don't log
- return;
- }
- $userid = empty($USER->id) ? '0' : $USER->id;
- }
-
- if (isset($CFG->logguests) and !$CFG->logguests) {
- if (!$userid or isguestuser($userid)) {
- return;
- }
- }
-
- $REMOTE_ADDR = getremoteaddr();
-
- $timenow = time();
- $info = $info;
- if (!empty($url)) { // could break doing html_entity_decode on an empty var.
- $url = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
- } else {
- $url = '';
- }
-
- // Restrict length of log lines to the space actually available in the
- // database so that it doesn't cause a DB error. Log a warning so that
- // developers can avoid doing things which are likely to cause this on a
- // routine basis.
- if(!empty($info) && core_text::strlen($info)>255) {
- $info = core_text::substr($info,0,252).'...';
- debugging('Warning: logged very long info',DEBUG_DEVELOPER);
- }
-
- // If the 100 field size is changed, also need to alter print_log in course/lib.php
- if(!empty($url) && core_text::strlen($url)>100) {
- $url = core_text::substr($url,0,97).'...';
- debugging('Warning: logged very long URL',DEBUG_DEVELOPER);
- }
-
- if (defined('MDL_PERFDB')) { global $PERF ; $PERF->logwrites++;};
-
- $log = array('time'=>$timenow, 'userid'=>$userid, 'course'=>$courseid, 'ip'=>$REMOTE_ADDR, 'module'=>$module,
- 'cmid'=>$cm, 'action'=>$action, 'url'=>$url, 'info'=>$info);
-
- try {
- $DB->insert_record_raw('log', $log, false);
- } catch (dml_exception $e) {
- debugging('Error: Could not insert a new entry to the Moodle log. '. $e->error, DEBUG_ALL);
-
- // MDL-11893, alert $CFG->supportemail if insert into log failed
- if ($CFG->supportemail and empty($CFG->noemailever)) {
- // email_to_user is not usable because email_to_user tries to write to the logs table,
- // and this will get caught in an infinite loop, if disk is full
- $site = get_site();
- $subject = 'Insert into log failed at your moodle site '.$site->fullname;
- $message = "Insert into log table failed at ". date('l dS \of F Y h:i:s A') .".\n It is possible that your disk is full.\n\n";
- $message .= "The failed query parameters are:\n\n" . var_export($log, true);
-
- $lasttime = get_config('admin', 'lastloginserterrormail');
- if(empty($lasttime) || time() - $lasttime > 60*60*24) { // limit to 1 email per day
- //using email directly rather than messaging as they may not be able to log in to access a message
- mail($CFG->supportemail, $subject, $message);
- set_config('lastloginserterrormail', time(), 'admin');
- }
- }
- }
-}
-
/**
* Store user last access times - called when use enters a course or site
*
diff --git a/lib/db/tasks.php b/lib/db/tasks.php
index 028a8e2354b..3526517ce10 100644
--- a/lib/db/tasks.php
+++ b/lib/db/tasks.php
@@ -59,15 +59,6 @@ $tasks = array(
'dayofweek' => '*',
'month' => '*'
),
- array(
- 'classname' => 'core\task\delete_logs_task',
- 'blocking' => 0,
- 'minute' => '0',
- 'hour' => '2',
- 'day' => '*',
- 'dayofweek' => '*',
- 'month' => '*'
- ),
array(
'classname' => 'core\task\backup_cleanup_task',
'blocking' => 0,
diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php
index 7368dc840ca..8a4916b17a0 100644
--- a/lib/deprecatedlib.php
+++ b/lib/deprecatedlib.php
@@ -30,6 +30,36 @@
defined('MOODLE_INTERNAL') || die();
+/**
+ * Add an entry to the log table.
+ *
+ * Add an entry to the log table. These are "action" focussed rather
+ * than web server hits, and provide a way to easily reconstruct what
+ * any particular student has been doing.
+ *
+ * @deprecated since 2.7 use new events instead
+ *
+ * @param int $courseid The course id
+ * @param string $module The module name e.g. forum, journal, resource, course, user etc
+ * @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify.
+ * @param string $url The file and parameters used to see the results of the action
+ * @param string $info Additional description information
+ * @param int $cm The course_module->id if there is one
+ * @param int|stdClass $user If log regards $user other than $USER
+ * @return void
+ */
+function add_to_log($courseid, $module, $action, $url='', $info='', $cm=0, $user=0) {
+ // TODO: Uncomment after all add_to_log() are removed from standard distribution - ideally before 2.7 release.
+ //debugging('ideally all add_to_log() calls should be replaced() with new events', DEBUG_DEVELOPER);
+
+ // This is a nasty hack that allows us to put all the legacy stuff into legacy storage,
+ // this way we may move all the legacy settings there too.
+ $manager = get_log_manager();
+ if (method_exists($manager, 'legacy_add_to_log')) {
+ $manager->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user);
+ }
+}
+
/**
* Adds a file upload to the log table so that clam can resolve the filename to the user later if necessary
*
@@ -4318,17 +4348,3 @@ function can_use_html_editor() {
debugging('can_use_html_editor has been deprecated please update your code to assume it returns true.', DEBUG_DEVELOPER);
return true;
}
-
-/**
- * Returns whether ajax is enabled/allowed or not.
- * This function is deprecated and always returns true.
- *
- * @param array $unused - not used any more.
- * @return bool
- * @deprecated since 2.7 MDL-33099 - please do not use this function any more.
- * @todo MDL-44088 This will be removed in Moodle 2.9.
- */
-function ajaxenabled(array $browsers = null) {
- debugging('ajaxenabled() is deprecated - please update your code to assume it returns true.', DEBUG_DEVELOPER);
- return true;
-}
diff --git a/lib/tests/event_test.php b/lib/tests/event_test.php
index 713fc14b649..2574f293311 100644
--- a/lib/tests/event_test.php
+++ b/lib/tests/event_test.php
@@ -566,6 +566,8 @@ class core_event_testcase extends advanced_testcase {
}
public function test_trigger_problems() {
+ $this->resetAfterTest(true);
+
$event = \core_tests\event\unittest_executed::create(array('courseid'=>1, 'context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
$event->trigger();
try {
@@ -597,6 +599,8 @@ class core_event_testcase extends advanced_testcase {
}
public function test_bad_events() {
+ $this->resetAfterTest(true);
+
try {
$event = \core_tests\event\unittest_executed::create(array('courseid'=>1, 'other'=>array('sample'=>5, 'xx'=>10)));
$this->fail('Exception expected when context and contextid missing');
@@ -654,7 +658,8 @@ class core_event_testcase extends advanced_testcase {
}
public function test_problematic_events() {
- global $CFG;
+ $this->resetAfterTest(true);
+
$event1 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance()));
$this->assertDebuggingNotCalled();
$this->assertNull($event1->xxx);
@@ -703,6 +708,8 @@ class core_event_testcase extends advanced_testcase {
public function test_record_snapshots() {
global $DB;
+ $this->resetAfterTest(true);
+
$event = \core_tests\event\unittest_executed::create(array('courseid'=>1, 'context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
$course1 = $DB->get_record('course', array('id'=>1));
$this->assertNotEmpty($course1);