MDL-52805 core: Remove legacy log plugin and more calls

This commit is contained in:
Mathew May
2023-03-07 13:08:46 +08:00
parent 5dace7abc8
commit 33ebbddde2
36 changed files with 39 additions and 2014 deletions
-16
View File
@@ -296,7 +296,6 @@ class core_admin_renderer extends plugin_renderer_base {
$output .= $this->header();
$output .= $this->output->heading(get_string('notifications', 'admin'));
$output .= $this->maturity_info($maturity);
$output .= $this->legacy_log_store_writing_error();
$output .= empty($CFG->disableupdatenotifications) ? $this->available_updates($availableupdates, $availableupdatesfetch) : '';
$output .= $this->insecure_dataroot_warning($insecuredataroot);
$output .= $this->development_libs_directories_warning($devlibdir);
@@ -2192,21 +2191,6 @@ class core_admin_renderer extends plugin_renderer_base {
return $output;
}
/**
* Check to see if writing to the deprecated legacy log store is enabled.
*
* @return string An error message if writing to the legacy log store is enabled.
*/
protected function legacy_log_store_writing_error() {
$enabled = get_config('logstore_legacy', 'loglegacy');
$plugins = explode(',', get_config('tool_log', 'enabled_stores'));
$enabled = $enabled && in_array('logstore_legacy', $plugins);
if ($enabled) {
return $this->warning(get_string('legacylogginginuse'));
}
}
/**
* Display message about the benefits of registering on Moodle.org
*
-25
View File
@@ -199,29 +199,4 @@ class manager implements \core\log\manager {
$this->readers = null;
$this->writers = null;
}
/**
* 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
* @param string $ip Override the IP, should only be used for restore.
* @param int $time Override the log time, should only be used for restore.
*/
public function legacy_add_to_log($courseid, $module, $action, $url = '', $info = '',
$cm = 0, $user = 0, $ip = null, $time = null) {
$this->init();
if (isset($this->stores['logstore_legacy'])) {
$this->stores['logstore_legacy']->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user, $ip, $time);
}
}
}
-11
View File
@@ -37,16 +37,5 @@ function xmldb_tool_log_install() {
$enabled[] = 'logstore_standard';
}
// Enable legacy log reading, but only if there are existing data.
if (file_exists("$CFG->dirroot/$CFG->admin/tool/log/store/legacy")) {
unset_config('loglegacy', 'logstore_legacy');
// Do not enabled legacy logging if somebody installed a new
// site and in less than one day upgraded to 2.7.
$params = array('yesterday' => time() - 60*60*24);
if ($DB->record_exists_select('log', "time < :yesterday", $params)) {
$enabled[] = 'logstore_legacy';
}
}
set_config('enabled_stores', implode(',', $enabled), 'tool_log');
}
@@ -1,53 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace logstore_legacy\event;
defined('MOODLE_INTERNAL') || die();
/**
* Legacy log emulation event class.
*
* @package core
* @since Moodle 2.7
* @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('eventlegacylogged', '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);
}
}
@@ -1,424 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Legacy log reader.
* @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead.
* @todo MDL-52805 This is to be removed in Moodle 3.10
*
* @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\sql_reader {
use \tool_log\helper\store,
\tool_log\helper\reader;
/**
* @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead.
* @todo MDL-52805 This is to be removed in Moodle 3.10
*
* @param \tool_log\log\manager $manager
*/
public function __construct(\tool_log\log\manager $manager) {
$this->helper_setup($manager);
}
/** @var array list of db fields which needs to be replaced for legacy log query */
protected static $standardtolegacyfields = array(
'timecreated' => 'time',
'courseid' => 'course',
'contextinstanceid' => 'cmid',
'origin' => 'ip',
'anonymous' => 0,
);
/** @var string Regex to replace the crud params */
const CRUD_REGEX = "/(crud).*?(<>|=|!=).*?'(.*?)'/s";
/**
* This method contains mapping required for Moodle core to make legacy store compatible with other sql_reader based
* queries.
*
* @param string $selectwhere Select statment
* @param array $params params for the sql
* @param string $sort sort fields
*
* @return array returns an array containing the sql predicate, an array of params and sorting parameter.
*/
protected static function replace_sql_legacy($selectwhere, array $params, $sort = '') {
// Following mapping is done to make can_delete_course() compatible with legacy store.
if ($selectwhere == "userid = :userid AND courseid = :courseid AND eventname = :eventname AND timecreated > :since" and
empty($sort)) {
$replace = "module = 'course' AND action = 'new' AND userid = :userid AND url = :url AND time > :since";
$params += array('url' => "view.php?id={$params['courseid']}");
return array($replace, $params, $sort);
}
// Replace db field names to make it compatible with legacy log.
foreach (self::$standardtolegacyfields as $from => $to) {
$selectwhere = str_replace($from, $to, $selectwhere);
if (!empty($sort)) {
$sort = str_replace($from, $to, $sort);
}
if (isset($params[$from])) {
$params[$to] = $params[$from];
unset($params[$from]);
}
}
// Replace crud fields.
$selectwhere = preg_replace_callback("/(crud).*?(<>|=|!=).*?'(.*?)'/s", self::class .'::replace_crud', $selectwhere);
return array($selectwhere, $params, $sort);
}
/**
* @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead.
* @todo MDL-52805 This will be removed in Moodle 3.10
*
* @param string $selectwhere
* @param array $params
* @param string $sort
* @param int $limitfrom
* @param int $limitnum
* @return array
*/
public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
global $DB;
$sort = self::tweak_sort_by_id($sort);
// Replace the query with hardcoded mappings required for core.
list($selectwhere, $params, $sort) = self::replace_sql_legacy($selectwhere, $params, $sort);
$records = array();
try {
// A custom report + on the fly SQL rewriting = a possible exception.
$records = $DB->get_recordset_select('log', $selectwhere, $params, $sort, '*', $limitfrom, $limitnum);
} catch (\moodle_exception $ex) {
debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER);
return array();
}
$events = array();
foreach ($records as $data) {
$events[$data->id] = $this->get_log_event($data);
}
$records->close();
return $events;
}
/**
* Get whether events are present for the given select clause.
* @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead.
*
* @param string $selectwhere select conditions.
* @param array $params params.
*
* @return bool Whether events available for the given conditions
*/
public function get_events_select_exists(string $selectwhere, array $params): bool {
global $DB;
// Replace the query with hardcoded mappings required for core.
list($selectwhere, $params) = self::replace_sql_legacy($selectwhere, $params);
try {
return $DB->record_exists_select('log', $selectwhere, $params);
} catch (\moodle_exception $ex) {
debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER);
return false;
}
}
/**
* Fetch records using given criteria returning a Traversable object.
* @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead.
* @todo MDL-52805 This will be removed in Moodle 3.10
*
* Note that the traversable object contains a moodle_recordset, so
* remember that is important that you call close() once you finish
* using it.
*
* @param string $selectwhere
* @param array $params
* @param string $sort
* @param int $limitfrom
* @param int $limitnum
* @return \Traversable|\core\event\base[]
*/
public function get_events_select_iterator($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
global $DB;
$sort = self::tweak_sort_by_id($sort);
// Replace the query with hardcoded mappings required for core.
list($selectwhere, $params, $sort) = self::replace_sql_legacy($selectwhere, $params, $sort);
try {
$recordset = $DB->get_recordset_select('log', $selectwhere, $params, $sort, '*', $limitfrom, $limitnum);
} catch (\moodle_exception $ex) {
debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER);
return new \EmptyIterator;
}
return new \core\dml\recordset_walk($recordset, array($this, 'get_log_event'));
}
/**
* Returns an event from the log data.
* @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead.
* @todo MDL-52805 This will be removed in Moodle 3.10
*
* @param stdClass $data Log data
* @return \core\event\base
*/
public function get_log_event($data) {
return \logstore_legacy\event\legacy_logged::restore_legacy($data);
}
/**
* @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead.
* @todo MDL-52805 This will be removed in Moodle 3.10
*
* @param string $selectwhere
* @param array $params
* @return int
*/
public function get_events_select_count($selectwhere, array $params) {
global $DB;
// Replace the query with hardcoded mappings required for core.
list($selectwhere, $params) = self::replace_sql_legacy($selectwhere, $params);
try {
return $DB->count_records_select('log', $selectwhere, $params);
} catch (\moodle_exception $ex) {
debugging("error converting legacy event data " . $ex->getMessage() . $ex->debuginfo, DEBUG_DEVELOPER);
return 0;
}
}
/**
* Are the new events appearing in the reader?
* @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead.
* @todo MDL-52805 This will be removed in Moodle 3.10
*
* @return bool true means new log events are being added, false means no new data will be added
*/
public function is_logging() {
return (bool)$this->get_config('loglegacy', true);
}
/**
* @deprecated since Moodle 3.6 MDL-52953 - Please use supported log stores such as "standard" or "external" instead.
* @todo MDL-52805 This will be removed in Moodle 3.10
*/
public function dispose() {
}
/**
* Legacy add_to_log() code.
* @deprecated since Moodle 3.1 MDL-45104 - Please use supported log stores such as "standard" or "external" instead.
* @todo MDL-52805 This will be removed in Moodle 3.3
*
* @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
* @param string $ip Override the IP, should only be used for restore.
* @param int $time Override the log time, should only be used for restore.
*/
public function legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user, $ip = null, $time = null) {
// 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->is_logging()) {
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;
}
}
$remoteaddr = (is_null($ip)) ? getremoteaddr() : $ip;
$timenow = (is_null($time)) ? time() : $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 (\core_text::strlen($action) > 40) {
$action = \core_text::substr($action, 0, 37) . '...';
debugging('Warning: logged very long action', DEBUG_DEVELOPER);
}
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' => $remoteaddr,
'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->errorcode, 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');
}
}
}
}
/**
* Generate a replace string for crud related sql conditions. This function is called as callback to preg_replace_callback()
* on the actual sql.
*
* @param array $match matched string for the passed pattern
*
* @return string The sql string to use instead of original
*/
protected static function replace_crud($match) {
$return = '';
unset($match[0]); // The first entry is the whole string.
foreach ($match as $m) {
// We hard code LIKE here because we are not worried about case sensitivity and want this to be fast.
switch ($m) {
case 'crud' :
$replace = 'action';
break;
case 'c' :
switch ($match[2]) {
case '=' :
$replace = " LIKE '%add%'";
break;
case '!=' :
case '<>' :
$replace = " NOT LIKE '%add%'";
break;
default:
$replace = '';
}
break;
case 'r' :
switch ($match[2]) {
case '=' :
$replace = " LIKE '%view%' OR action LIKE '%report%'";
break;
case '!=' :
case '<>' :
$replace = " NOT LIKE '%view%' AND action NOT LIKE '%report%'";
break;
default:
$replace = '';
}
break;
case 'u' :
switch ($match[2]) {
case '=' :
$replace = " LIKE '%update%'";
break;
case '!=' :
case '<>' :
$replace = " NOT LIKE '%update%'";
break;
default:
$replace = '';
}
break;
case 'd' :
switch ($match[2]) {
case '=' :
$replace = " LIKE '%delete%'";
break;
case '!=' :
case '<>' :
$replace = " NOT LIKE '%delete%'";
break;
default:
$replace = '';
}
break;
default :
$replace = '';
}
$return .= $replace;
}
return $return;
}
}
@@ -1,255 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Data provider.
*
* @package logstore_legacy
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_legacy\privacy;
defined('MOODLE_INTERNAL') || die();
use context;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use tool_log\local\privacy\helper;
/**
* Data provider class.
*
* @package logstore_legacy
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\tool_log\local\privacy\logstore_provider,
\tool_log\local\privacy\logstore_userlist_provider {
/**
* Returns metadata.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection) : collection {
$collection->add_external_location_link('log', [
'time' => 'privacy:metadata:log:time',
'userid' => 'privacy:metadata:log:userid',
'ip' => 'privacy:metadata:log:ip',
'action' => 'privacy:metadata:log:action',
'url' => 'privacy:metadata:log:url',
'info' => 'privacy:metadata:log:info',
], 'privacy:metadata:log');
return $collection;
}
/**
* Add contexts that contain user information for the specified user.
*
* @param contextlist $contextlist The contextlist to add the contexts to.
* @param int $userid The user to find the contexts for.
* @return void
*/
public static function add_contexts_for_userid(contextlist $contextlist, $userid) {
$sql = "
SELECT ctx.id
FROM {context} ctx
JOIN {log} l
ON (l.cmid = 0 AND l.course = ctx.instanceid AND ctx.contextlevel = :courselevel)
OR (l.cmid > 0 AND l.cmid = ctx.instanceid AND ctx.contextlevel = :modulelevel)
OR (l.course <= 0 AND ctx.id = :syscontextid)
WHERE l.userid = :userid";
$params = [
'courselevel' => CONTEXT_COURSE,
'modulelevel' => CONTEXT_MODULE,
'syscontextid' => SYSCONTEXTID,
'userid' => $userid,
];
$contextlist->add_from_sql($sql, $params);
}
/**
* Add user IDs that contain user information for the specified context.
*
* @param \core_privacy\local\request\userlist $userlist The userlist to add the users to.
* @return void
*/
public static function add_userids_for_context(\core_privacy\local\request\userlist $userlist) {
$context = $userlist->get_context();
list($insql, $params) = static::get_sql_where_from_contexts([$context]);
$sql = "SELECT l.userid
FROM {log} l
WHERE $insql";
$userlist->add_from_sql('userid', $sql, $params);
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
$userid = $contextlist->get_user()->id;
list($insql, $inparams) = static::get_sql_where_from_contexts($contextlist->get_contexts());
if (empty($insql)) {
return;
}
$sql = "userid = :userid AND $insql";
$params = array_merge($inparams, ['userid' => $userid]);
$path = [get_string('privacy:path:logs', 'tool_log'), get_string('pluginname', 'logstore_legacy')];
$flush = function($lastcontextid, $data) use ($path) {
$context = context::instance_by_id($lastcontextid);
writer::with_context($context)->export_data($path, (object) ['logs' => $data]);
};
$lastcontextid = null;
$data = [];
$recordset = $DB->get_recordset_select('log', $sql, $params, 'course, cmid, time, id');
foreach ($recordset as $record) {
$event = \logstore_legacy\event\legacy_logged::restore_legacy($record);
$context = $event->get_context();
if ($lastcontextid && $lastcontextid != $context->id) {
$flush($lastcontextid, $data);
$data = [];
}
$extra = $event->get_logextra();
$data[] = [
'name' => $event->get_name(),
'description' => $event->get_description(),
'timecreated' => transform::datetime($event->timecreated),
'ip' => $extra['ip'],
'origin' => helper::transform_origin($extra['origin']),
];
$lastcontextid = $context->id;
}
if ($lastcontextid) {
$flush($lastcontextid, $data);
}
$recordset->close();
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(context $context) {
global $DB;
list($sql, $params) = static::get_sql_where_from_contexts([$context]);
if (empty($sql)) {
return;
}
$DB->delete_records_select('log', $sql, $params);
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;
list($sql, $params) = static::get_sql_where_from_contexts($contextlist->get_contexts());
if (empty($sql)) {
return;
}
$userid = $contextlist->get_user()->id;
$DB->delete_records_select('log', "$sql AND userid = :userid", array_merge($params, ['userid' => $userid]));
}
/**
* Delete all data for a list of users in the specified context.
*
* @param \core_privacy\local\request\approved_userlist $userlist The specific context and users to delete data for.
* @return void
*/
public static function delete_data_for_userlist(\core_privacy\local\request\approved_userlist $userlist) {
global $DB;
list($sql, $params) = static::get_sql_where_from_contexts([$userlist->get_context()]);
if (empty($sql)) {
return;
}
list($usersql, $userparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
$params = array_merge($params, $userparams);
$DB->delete_records_select('log', "$sql AND userid $usersql", $params);
}
/**
* Get an SQL where statement from a list of contexts.
*
* @param array $contexts The contexts.
* @return array [$sql, $params]
*/
protected static function get_sql_where_from_contexts(array $contexts) {
global $DB;
$sorted = array_reduce($contexts, function ($carry, $context) {
$level = $context->contextlevel;
if ($level == CONTEXT_MODULE || $level == CONTEXT_COURSE) {
$carry[$level][] = $context->instanceid;
} else if ($level == CONTEXT_SYSTEM) {
$carry[$level] = $context->id;
}
return $carry;
}, [
CONTEXT_COURSE => [],
CONTEXT_MODULE => [],
CONTEXT_SYSTEM => null,
]);
$sqls = [];
$params = [];
if (!empty($sorted[CONTEXT_MODULE])) {
list($insql, $inparams) = $DB->get_in_or_equal($sorted[CONTEXT_MODULE], SQL_PARAMS_NAMED);
$sqls[] = "cmid $insql";
$params = array_merge($params, $inparams);
}
if (!empty($sorted[CONTEXT_COURSE])) {
list($insql, $inparams) = $DB->get_in_or_equal($sorted[CONTEXT_COURSE], SQL_PARAMS_NAMED);
$sqls[] = "cmid = 0 AND course $insql";
$params = array_merge($params, $inparams);
}
if (!empty($sorted[CONTEXT_SYSTEM])) {
$sqls[] = "course <= 0";
}
if (empty($sqls)) {
return [null, null];
}
return ['((' . implode(') OR (', $sqls) . '))', $params];
}
}
@@ -1,69 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Legacy log reader.
*
* @package logstore_legacy
* @copyright 2014 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_legacy\task;
defined('MOODLE_INTERNAL') || die();
class cleanup_task extends \core\task\scheduled_task {
/**
* Get a descriptive name for this task (shown to admins).
*
* @return string
*/
public function get_name() {
return get_string('taskcleanup', 'logstore_legacy');
}
/**
* Do the job.
* Throw exceptions on errors (the job will be retried).
*/
public function execute() {
global $CFG, $DB;
if (empty($CFG->loglifetime)) {
return;
}
$loglifetime = time() - ($CFG->loglifetime * 3600 * 24); // Value in days.
$lifetimep = array($loglifetime);
$start = time();
while ($min = $DB->get_field_select("log", "MIN(time)", "time < ?", $lifetimep)) {
// Break this down into chunks to avoid transaction for too long and generally thrashing database.
// Experiments suggest deleting one day takes up to a few seconds; probably a reasonable chunk size usually.
// If the cleanup has just been enabled, it might take e.g a month to clean the years of logs.
$params = array(min($min + 3600 * 24, $loglifetime));
$DB->delete_records_select("log", "time < ?", $params);
if (time() > $start + 300) {
// Do not churn on log deletion for too long each run.
break;
}
}
mtrace(" Deleted old legacy log records");
}
}
-37
View File
@@ -1,37 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Legacy log reader cron task.
*
* @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();
$tasks = array(
array(
'classname' => '\logstore_legacy\task\cleanup_task',
'blocking' => 0,
'minute' => 'R',
'hour' => '5',
'day' => '*',
'dayofweek' => '*',
'month' => '*'
),
);
@@ -1,37 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* 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['eventlegacylogged'] = 'Legacy event logged';
$string['loglegacy'] = 'Log legacy data';
$string['loglegacy_help'] = 'This plugin records log data to the legacy log table (mdl_log). This functionality has been replaced by newer, richer and more efficient logging plugins, so you should only run this plugin if you have old custom reports that directly query the old log table. Writing to the legacy logs will increase load, so it is recommended that you disable this plugin for performance reasons when it is not needed.';
$string['pluginname'] = 'Legacy log';
$string['pluginname_desc'] = 'A log plugin that stores log entries in the legacy log table.';
$string['privacy:metadata:log'] = 'A collection of past events';
$string['privacy:metadata:log:action'] = 'A description of the action';
$string['privacy:metadata:log:info'] = 'Additional information';
$string['privacy:metadata:log:ip'] = 'The IP address used at the time of the event';
$string['privacy:metadata:log:time'] = 'The time when the action took place';
$string['privacy:metadata:log:url'] = 'The URL related to the event';
$string['privacy:metadata:log:userid'] = 'The ID of the user who performed the action';
$string['taskcleanup'] = 'Legacy log table cleanup';
-52
View File
@@ -1,52 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* 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));
}
-47
View File
@@ -1,47 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Fixtures for legacy logging testing.
*
* @package logstore_legacy
* @copyright 2014 Petr Skoda
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_legacy\event;
defined('MOODLE_INTERNAL') || die();
class unittest_executed extends \core\event\base {
public static function get_name() {
return 'xxx';
}
public function get_description() {
return 'yyy';
}
protected function init() {
$this->data['crud'] = 'u';
$this->data['edulevel'] = self::LEVEL_PARTICIPATING;
}
public function get_url() {
return new \moodle_url('/somepath/somefile.php', array('id' => $this->data['other']['sample']));
}
}
-43
View File
@@ -1,43 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Fixtures for legacy logging testing.
*
* @package logstore_legacy
* @copyright 2014 onwards Ankit Agarwal <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_legacy\test;
defined('MOODLE_INTERNAL') || die();
class unittest_logstore_legacy extends \logstore_legacy\log\store {
/**
* Wrapper to make protected method accessible during testing.
*
* @param string $select sql predicate.
* @param array $params sql params.
* @param string $sort sort options.
*
* @return array returns array of sql predicate, params and sorting criteria.
*/
public static function replace_sql_legacy($select, array $params, $sort = '') {
return parent::replace_sql_legacy($select, $params, $sort);
}
}
@@ -1,472 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Data provider tests.
*
* @package logstore_legacy
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace logstore_legacy\privacy;
defined('MOODLE_INTERNAL') || die();
global $CFG;
use core_privacy\tests\provider_testcase;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
use logstore_legacy\privacy\provider;
use logstore_legacy\event\unittest_executed;
require_once(__DIR__ . '/../fixtures/event.php');
/**
* Data provider testcase class.
*
* @package logstore_legacy
* @category test
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends provider_testcase {
public function setUp(): void {
$this->resetAfterTest();
}
public function test_get_contexts_for_userid() {
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$c1 = $this->getDataGenerator()->create_course();
$cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
$sysctx = \context_system::instance();
$c1ctx = \context_course::instance($c1->id);
$cm1ctx = \context_module::instance($cm1->cmid);
$this->enable_logging();
$manager = get_log_manager(true);
// User 1 is the author.
$this->setUser($u1);
$this->assert_contextlist_equals($this->get_contextlist_for_user($u1), []);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 1]]);
$e->trigger();
$this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$cm1ctx]);
// User 2 is the author.
$this->setUser($u2);
$this->assert_contextlist_equals($this->get_contextlist_for_user($u2), []);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 2]]);
$e->trigger();
$this->assert_contextlist_equals($this->get_contextlist_for_user($u2), [$cm1ctx]);
// User 3 is the author.
$this->setUser($u3);
$this->assert_contextlist_equals($this->get_contextlist_for_user($u3), []);
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 3]]);
$e->trigger();
$this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx]);
}
/**
* Test returning user IDs for a given context.
*/
public function test_add_userids_for_context() {
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$module = $this->getDataGenerator()->create_module('url', ['course' => $course]);
$sysctx = \context_system::instance();
$c1ctx = \context_course::instance($course->id);
$cm1ctx = \context_module::instance($module->cmid);
$userctx = \context_user::instance($u1->id);
$this->enable_logging();
$manager = get_log_manager(true);
$this->setUser($u1);
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 1]]);
$e->trigger();
$this->setUser($u2);
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 2]]);
$e->trigger();
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 3]]);
$e->trigger();
$this->setUser($u3);
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 4]]);
$e->trigger();
$this->setUser($u1);
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 5]]);
$e->trigger();
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 6]]);
$e->trigger();
$this->setUser($u2);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 7]]);
$e->trigger();
$this->setUser($u3);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 8]]);
$e->trigger();
// Start with system and check that each of the contexts returns what we expected.
$userlist = new \core_privacy\local\request\userlist($sysctx, 'logstore_legacy');
provider::add_userids_for_context($userlist);
$systemuserids = $userlist->get_userids();
$this->assertCount(2, $systemuserids);
$this->assertNotFalse(array_search($u1->id, $systemuserids));
$this->assertNotFalse(array_search($u2->id, $systemuserids));
// Check the course context.
$userlist = new \core_privacy\local\request\userlist($c1ctx, 'logstore_legacy');
provider::add_userids_for_context($userlist);
$courseuserids = $userlist->get_userids();
$this->assertCount(2, $courseuserids);
$this->assertNotFalse(array_search($u1->id, $courseuserids));
$this->assertNotFalse(array_search($u3->id, $courseuserids));
// Check the module context.
$userlist = new \core_privacy\local\request\userlist($cm1ctx, 'logstore_legacy');
provider::add_userids_for_context($userlist);
$moduleuserids = $userlist->get_userids();
$this->assertCount(3, $moduleuserids);
$this->assertNotFalse(array_search($u1->id, $moduleuserids));
$this->assertNotFalse(array_search($u2->id, $moduleuserids));
$this->assertNotFalse(array_search($u3->id, $moduleuserids));
}
public function test_delete_data_for_user() {
global $DB;
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$c1 = $this->getDataGenerator()->create_course();
$c2 = $this->getDataGenerator()->create_course();
$cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
$sysctx = \context_system::instance();
$c1ctx = \context_course::instance($c1->id);
$c2ctx = \context_course::instance($c2->id);
$cm1ctx = \context_module::instance($cm1->cmid);
$this->enable_logging();
$manager = get_log_manager(true);
// User 1 is the author.
$this->setUser($u1);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 1]]);
$e->trigger();
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 2]]);
$e->trigger();
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 3]]);
$e->trigger();
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 4]]);
$e->trigger();
// User 2 is the author.
$this->setUser($u2);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 5]]);
$e->trigger();
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 6]]);
$e->trigger();
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 7]]);
$e->trigger();
// Assert what we have.
$this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
$this->assertEquals(4, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
// Delete other context.
provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_legacy', [$c2ctx->id]));
$this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
$this->assertEquals(4, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
// Delete system.
provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_legacy', [$sysctx->id]));
$this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
$this->assertEquals(3, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
// Delete course.
provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_legacy', [$c1ctx->id]));
$this->assertTrue($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
$this->assertEquals(2, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
// Delete course.
provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_legacy', [$cm1ctx->id]));
$this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['userid' => $u1->id, 'cmid' => 0, 'course' => 0]));
$this->assertEquals(0, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
}
public function test_delete_data_for_all_users_in_context() {
global $DB;
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$c1 = $this->getDataGenerator()->create_course();
$c2 = $this->getDataGenerator()->create_course();
$cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
$sysctx = \context_system::instance();
$c1ctx = \context_course::instance($c1->id);
$c2ctx = \context_course::instance($c2->id);
$cm1ctx = \context_module::instance($cm1->cmid);
$this->enable_logging();
$manager = get_log_manager(true);
// User 1 is the author.
$this->setUser($u1);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 1]]);
$e->trigger();
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 2]]);
$e->trigger();
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 3]]);
$e->trigger();
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 4]]);
$e->trigger();
// User 2 is the author.
$this->setUser($u2);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 5]]);
$e->trigger();
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 6]]);
$e->trigger();
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 7]]);
$e->trigger();
// Assert what we have.
$this->assertTrue($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
$this->assertEquals(4, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
// Delete other context.
provider::delete_data_for_all_users_in_context($c2ctx);
$this->assertTrue($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
$this->assertEquals(4, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(3, $DB->count_records('log', ['userid' => $u2->id]));
// Delete system.
provider::delete_data_for_all_users_in_context($sysctx);
$this->assertTrue($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertTrue($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
$this->assertEquals(3, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(2, $DB->count_records('log', ['userid' => $u2->id]));
// Delete course.
provider::delete_data_for_all_users_in_context($c1ctx);
$this->assertTrue($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
$this->assertEquals(2, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(1, $DB->count_records('log', ['userid' => $u2->id]));
// Delete course.
provider::delete_data_for_all_users_in_context($cm1ctx);
$this->assertFalse($DB->record_exists('log', ['cmid' => $cm1->cmid, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => $c1->id]));
$this->assertFalse($DB->record_exists('log', ['cmid' => 0, 'course' => 0]));
$this->assertEquals(0, $DB->count_records('log', ['userid' => $u1->id]));
$this->assertEquals(0, $DB->count_records('log', ['userid' => $u2->id]));
}
/**
* Test the deletion of data for a list of users in a context.
*/
public function test_delete_data_for_userlist() {
global $DB;
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$module = $this->getDataGenerator()->create_module('url', ['course' => $course]);
$sysctx = \context_system::instance();
$c1ctx = \context_course::instance($course->id);
$cm1ctx = \context_module::instance($module->cmid);
$userctx = \context_user::instance($u1->id);
$this->enable_logging();
$manager = get_log_manager(true);
$this->setUser($u1);
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 1]]);
$e->trigger();
$this->setUser($u2);
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 2]]);
$e->trigger();
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 3]]);
$e->trigger();
$this->setUser($u3);
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 4]]);
$e->trigger();
$this->setUser($u1);
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 5]]);
$e->trigger();
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 6]]);
$e->trigger();
$this->setUser($u2);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 7]]);
$e->trigger();
$this->setUser($u3);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 8]]);
$e->trigger();
// System context deleting one user.
$this->assertEquals(3, $DB->count_records('log', ['cmid' => 0, 'course' => 0]));
$userlist = new \core_privacy\local\request\approved_userlist($sysctx, 'logstore_legacy', [$u2->id]);
provider::delete_data_for_userlist($userlist);
$this->assertEquals(1, $DB->count_records('log', ['cmid' => 0, 'course' => 0]));
// Course context deleting one user.
$this->assertEquals(2, $DB->count_records('log', ['cmid' => 0, 'course' => $course->id]));
$userlist = new \core_privacy\local\request\approved_userlist($c1ctx, 'logstore_legacy', [$u1->id]);
provider::delete_data_for_userlist($userlist);
$this->assertEquals(1, $DB->count_records('log', ['cmid' => 0, 'course' => $course->id]));
// Module context deleting two users.
$this->assertEquals(3, $DB->count_records('log', ['cmid' => $module->cmid, 'course' => $course->id]));
$userlist = new \core_privacy\local\request\approved_userlist($cm1ctx, 'logstore_legacy', [$u1->id, $u3->id]);
provider::delete_data_for_userlist($userlist);
$this->assertEquals(1, $DB->count_records('log', ['cmid' => $module->cmid, 'course' => $course->id]));
}
public function test_export_data_for_user() {
global $DB;
$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$c1 = $this->getDataGenerator()->create_course();
$c2 = $this->getDataGenerator()->create_course();
$cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
$sysctx = \context_system::instance();
$c1ctx = \context_course::instance($c1->id);
$c2ctx = \context_course::instance($c2->id);
$cm1ctx = \context_module::instance($cm1->cmid);
$this->enable_logging();
$manager = get_log_manager(true);
$path = [get_string('privacy:path:logs', 'tool_log'), get_string('pluginname', 'logstore_legacy')];
// User 1 is the author.
$this->setUser($u1);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 1]]);
$e->trigger();
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 2]]);
$e->trigger();
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 3]]);
$e->trigger();
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 4]]);
$e->trigger();
// User 2 is the author.
$this->setUser($u2);
$e = unittest_executed::create(['context' => $cm1ctx, 'other' => ['sample' => 5]]);
$e->trigger();
$e = unittest_executed::create(['context' => $c1ctx, 'other' => ['sample' => 6]]);
$e->trigger();
$e = unittest_executed::create(['context' => $sysctx, 'other' => ['sample' => 7]]);
$e->trigger();
// Test export.
provider::export_user_data(new approved_contextlist($u1, 'logstore_legacy', [$cm1ctx->id]));
$data = writer::with_context($c1ctx)->get_data($path);
$this->assertEmpty($data);
$data = writer::with_context($cm1ctx)->get_data($path);
$this->assertCount(2, $data->logs);
writer::reset();
provider::export_user_data(new approved_contextlist($u1, 'logstore_legacy', [$c1ctx->id]));
$data = writer::with_context($cm1ctx)->get_data($path);
$this->assertEmpty($data);
$data = writer::with_context($c1ctx)->get_data($path);
$this->assertCount(1, $data->logs);
writer::reset();
provider::export_user_data(new approved_contextlist($u1, 'logstore_legacy', [$sysctx->id]));
$data = writer::with_context($sysctx)->get_data($path);
$this->assertCount(1, $data->logs);
}
/**
* Assert the content of a context list.
*
* @param contextlist $contextlist The collection.
* @param array $expected List of expected contexts or IDs.
* @return void
*/
protected function assert_contextlist_equals($contextlist, array $expected) {
$expectedids = array_map(function($context) {
if (is_object($context)) {
return $context->id;
}
return $context;
}, $expected);
$contextids = array_map('intval', $contextlist->get_contextids());
sort($contextids);
sort($expectedids);
$this->assertEquals($expectedids, $contextids);
}
/**
* Enable logging.
*
* @return void
*/
protected function enable_logging() {
set_config('enabled_stores', 'logstore_legacy', 'tool_log');
set_config('loglegacy', 1, 'logstore_legacy');
get_log_manager(true);
}
/**
* Get the contextlist for a user.
*
* @param object $user The user.
* @return contextlist
*/
protected function get_contextlist_for_user($user) {
$contextlist = new contextlist();
provider::add_contexts_for_userid($contextlist, $user->id);
return $contextlist;
}
}
@@ -1,264 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace logstore_legacy;
defined('MOODLE_INTERNAL') || die();
require_once(__DIR__ . '/fixtures/event.php');
require_once(__DIR__ . '/fixtures/store.php');
/**
* Legacy log store tests.
*
* @package logstore_legacy
* @copyright 2014 Petr Skoda {@link http://skodak.org/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class store_test extends \advanced_testcase {
public function test_log_writing() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$user1 = $this->getDataGenerator()->create_user();
$course1 = $this->getDataGenerator()->create_course();
$module1 = $this->getDataGenerator()->create_module('resource', array('course' => $course1));
$course2 = $this->getDataGenerator()->create_course();
// Enable legacy logging plugin.
set_config('enabled_stores', 'logstore_legacy', 'tool_log');
set_config('loglegacy', 1, 'logstore_legacy');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
$this->assertCount(1, $stores);
$this->assertEquals(array('logstore_legacy'), array_keys($stores));
$store = $stores['logstore_legacy'];
$this->assertInstanceOf('logstore_legacy\log\store', $store);
$this->assertInstanceOf('core\log\sql_reader', $store);
$this->assertTrue($store->is_logging());
$logs = $DB->get_records('log', array(), 'id ASC');
$this->assertCount(0, $logs);
$this->setCurrentTimeStart();
$this->setUser(0);
$event1 = \logstore_legacy\event\unittest_executed::create(
array('context' => \context_module::instance($module1->cmid), 'other' => array('sample' => 5, 'xx' => 10)));
$event1->trigger();
$this->setUser($user1);
$event2 = \logstore_legacy\event\unittest_executed::create(
array('context' => \context_course::instance($course2->id), 'other' => array('sample' => 6, 'xx' => 11)));
$event2->trigger();
$logs = $DB->get_records('log', array(), 'id ASC');
$this->assertCount(2, $logs);
$log = array_shift($logs);
$this->assertNotEmpty($log->id);
$this->assertTimeCurrent($log->time);
$this->assertEquals(0, $log->userid);
$this->assertSame('0.0.0.0', $log->ip);
$this->assertEquals($course1->id, $log->course);
$this->assertSame('core_unittest', $log->module);
$this->assertEquals($module1->cmid, $log->cmid);
$this->assertSame('view', $log->action);
$this->assertSame('unittest.php?id=5', $log->url);
$this->assertSame('bbb', $log->info);
$oldlogid = $log->id;
$log = array_shift($logs);
$this->assertGreaterThan($oldlogid, $log->id);
$this->assertNotEmpty($log->id);
$this->assertTimeCurrent($log->time);
$this->assertEquals($user1->id, $log->userid);
$this->assertSame('0.0.0.0', $log->ip);
$this->assertEquals($course2->id, $log->course);
$this->assertSame('core_unittest', $log->module);
$this->assertEquals(0, $log->cmid);
$this->assertSame('view', $log->action);
$this->assertSame('unittest.php?id=6', $log->url);
$this->assertSame('bbb', $log->info);
// Test if disabling works.
set_config('enabled_stores', 'logstore_legacy', 'tool_log');
set_config('loglegacy', 0, 'logstore_legacy');
$manager = get_log_manager(true);
$stores = $manager->get_readers();
$store = $stores['logstore_legacy'];
$this->assertFalse($store->is_logging());
\logstore_legacy\event\unittest_executed::create(
array('context' => \context_system::instance(), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(2, $DB->count_records('log'));
// Another way to disable legacy completely.
set_config('enabled_stores', 'logstore_standard', 'tool_log');
set_config('loglegacy', 1, 'logstore_legacy');
get_log_manager(true);
\logstore_legacy\event\unittest_executed::create(
array('context' => \context_system::instance(), 'other' => array('sample' => 5, 'xx' => 10)))->trigger();
$this->assertEquals(2, $DB->count_records('log'));
// Set everything back.
set_config('enabled_stores', '', 'tool_log');
set_config('loglegacy', 0, 'logstore_legacy');
get_log_manager(true);
}
/**
* Test replace_sql_legacy()
*/
public function test_replace_sql_legacy() {
$selectwhere = "userid = :userid AND courseid = :courseid AND eventname = :eventname AND timecreated > :since";
$params = array('userid' => 2, 'since' => 3, 'courseid' => 4, 'eventname' => '\core\event\course_created');
$expectedselect = "module = 'course' AND action = 'new' AND userid = :userid AND url = :url AND time > :since";
$expectedparams = $params + array('url' => "view.php?id=4");
list($replaceselect, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals($replaceselect, $expectedselect);
$this->assertEquals($replaceparams, $expectedparams);
// Test CRUD related changes.
$selectwhere = "edulevel = 0";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals($selectwhere, $updatewhere);
$selectwhere = "edulevel = 0 and crud = 'u'";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals("edulevel = 0 and action LIKE '%update%'", $updatewhere);
$selectwhere = "edulevel = 0 and crud != 'u'";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals("edulevel = 0 and action NOT LIKE '%update%'", $updatewhere);
$selectwhere = "edulevel = 0 and crud <> 'u'";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals("edulevel = 0 and action NOT LIKE '%update%'", $updatewhere);
$selectwhere = "edulevel = 0 and crud = 'r'";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals("edulevel = 0 and action LIKE '%view%' OR action LIKE '%report%'", $updatewhere);
$selectwhere = "edulevel = 0 and crud != 'r'";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals("edulevel = 0 and action NOT LIKE '%view%' AND action NOT LIKE '%report%'", $updatewhere);
$selectwhere = "edulevel = 0 and crud <> 'r'";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals("edulevel = 0 and action NOT LIKE '%view%' AND action NOT LIKE '%report%'", $updatewhere);
// The slq is incorrect, since quotes must not be present. Make sure this is not parsed.
$selectwhere = "edulevel = 0 and 'crud' != 'u'";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertNotEquals("edulevel = 0 and action NOT LIKE '%update%'", $updatewhere);
$selectwhere = "edulevel = 0 and crud = 'u' OR crud != 'r' or crud <> 'd'";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals("edulevel = 0 and action LIKE '%update%' OR action NOT LIKE '%view%' AND action NOT LIKE '%report%' or action NOT LIKE '%delete%'", $updatewhere);
// The anonymous select returns all data.
$selectwhere = "anonymous = 0";
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertSame("0 = 0", $updatewhere);
// Test legacy field names are mapped.
$selectwhere = "timecreated = :timecreated and courseid = :courseid and contextinstanceid = :contextinstanceid and origin = :origin";
$params = array('timecreated' => 2, 'courseid' => 3, 'contextinstanceid' => 4, 'origin' => 5 );
$expectedparams = array('time' => 2, 'course' => 3, 'cmid' => 4, 'ip' => 5);
list($updatewhere, $replaceparams) = \logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params);
$this->assertEquals("time = :time and course = :course and cmid = :cmid and ip = :ip", $updatewhere);
$this->assertSame($expectedparams, $replaceparams);
// Test sorting parameters.
$selectwhere = "courseid = 3";
$params = array();
$sort = 'timecreated DESC';
list($updatewhere, $replaceparams, $sort) =
\logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params, $sort);
$this->assertSame('time DESC', $sort);
$sort = 'courseid DESC';
list($updatewhere, $replaceparams, $sort) =
\logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params, $sort);
$this->assertSame('course DESC', $sort);
$sort = 'contextinstanceid DESC';
list($updatewhere, $replaceparams, $sort) =
\logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params, $sort);
$this->assertSame('cmid DESC', $sort);
$sort = 'origin DESC';
list($updatewhere, $replaceparams, $sort) =
\logstore_legacy\test\unittest_logstore_legacy::replace_sql_legacy($selectwhere, $params, $sort);
$this->assertSame('ip DESC', $sort);
}
/*
* Test logmanager::get_supported_reports returns all reports that require this store.
*/
public function test_get_supported_reports() {
$logmanager = get_log_manager();
$allreports = \core_component::get_plugin_list('report');
// Make sure all supported reports are installed.
$expectedreports = array_intersect_key([
'log' => 'report_log',
'loglive' => 'report_loglive',
'outline' => 'report_outline',
'participation' => 'report_participation',
'stats' => 'report_stats'
], $allreports);
$supportedreports = $logmanager->get_supported_reports('logstore_legacy');
foreach ($expectedreports as $expectedreport) {
$this->assertArrayHasKey($expectedreport, $supportedreports);
}
}
/**
* Test that the legacy log cleanup works correctly.
*/
public function test_cleanup_task() {
global $DB;
$this->resetAfterTest();
// Create some records spread over various days; test multiple iterations in cleanup.
$record = (object) array('time' => time());
$DB->insert_record('log', $record);
$record->time -= 3600 * 24 * 30;
$DB->insert_record('log', $record);
$record->time -= 3600 * 24 * 30;
$DB->insert_record('log', $record);
$record->time -= 3600 * 24 * 30;
$DB->insert_record('log', $record);
$this->assertEquals(4, $DB->count_records('log'));
// Remove all logs before "today".
set_config('loglifetime', 1);
$this->expectOutputString(" Deleted old legacy log records\n");
$clean = new \logstore_legacy\task\cleanup_task();
$clean->execute();
$this->assertEquals(1, $DB->count_records('log'));
}
}
-29
View File
@@ -1,29 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* 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 = 2022112800; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2022111800; // Requires this Moodle version.
$plugin->component = 'logstore_legacy'; // Full name of the plugin (used for diagnostics).
+3 -4
View File
@@ -36,15 +36,14 @@ class manager_test extends \advanced_testcase {
$this->assertCount(0, $stores);
$this->assertFileExists("$CFG->dirroot/$CFG->admin/tool/log/store/standard/version.php");
$this->assertFileExists("$CFG->dirroot/$CFG->admin/tool/log/store/legacy/version.php");
set_config('enabled_stores', 'logstore_standard,logstore_legacy', 'tool_log');
set_config('enabled_stores', 'logstore_standard', 'tool_log');
$manager = get_log_manager(true);
$this->assertInstanceOf('core\log\manager', $manager);
$stores = $manager->get_readers();
$this->assertIsArray($stores);
$this->assertCount(2, $stores);
$this->assertCount(1, $stores);
foreach ($stores as $key => $store) {
$this->assertIsString($key);
$this->assertInstanceOf('core\log\sql_reader', $store);
@@ -61,7 +60,7 @@ class manager_test extends \advanced_testcase {
$stores = $manager->get_readers('core\log\sql_reader');
$this->assertIsArray($stores);
$this->assertCount(2, $stores);
$this->assertCount(1, $stores);
foreach ($stores as $key => $store) {
$this->assertIsString($key);
$this->assertInstanceOf('core\log\sql_reader', $store);
+2 -1
View File
@@ -1745,6 +1745,7 @@ class core_plugin_manager {
'binarius', 'boxxie', 'brick', 'canvas', 'formal_white', 'formfactor', 'fusion', 'leatherbound',
'magazine', 'mymobile', 'nimble', 'nonzero', 'overlay', 'serenity', 'sky_high', 'splash',
'standard', 'standardold'),
'logstore' => ['legacy'],
'webservice' => array('amf', 'xmlrpc'),
);
@@ -1908,7 +1909,7 @@ class core_plugin_manager {
),
'logstore' => array(
'database', 'legacy', 'standard',
'database', 'standard',
),
'ltiservice' => array(
@@ -747,7 +747,7 @@ class summary_table extends table_sql {
foreach ($readers as $reader) {
// If reader is not a sql_internal_table_reader and not legacy store then return.
if (!($reader instanceof \core\log\sql_internal_table_reader) && !($reader instanceof logstore_legacy\log\store)) {
if (!($reader instanceof \core\log\sql_internal_table_reader)) {
continue;
}
$logreader = $reader;
@@ -770,14 +770,8 @@ class summary_table extends table_sql {
$this->create_log_summary_temp_table();
if ($this->logreader instanceof logstore_legacy\log\store) {
$logtable = 'log';
// Anonymous actions are never logged in legacy log.
$nonanonymous = '';
} else {
$logtable = $this->logreader->get_internal_log_table_name();
$nonanonymous = 'AND anonymous = 0';
}
$logtable = $this->logreader->get_internal_log_table_name();
$nonanonymous = 'AND anonymous = 0';
// Apply dates filter if applied.
$datewhere = $this->sql->filterbase['dateslog'] ?? '';
+1 -2
View File
@@ -54,7 +54,6 @@ class report_eventlist_list_generator {
// List of exceptional events that will cause problems if displayed.
$eventsignore = [
\core\event\unknown_logged::class,
\logstore_legacy\event\legacy_logged::class,
];
$eventinformation = [];
@@ -248,7 +247,7 @@ class report_eventlist_list_generator {
if (method_exists($plugineventname, 'get_static_info')) {
if ($detail) {
$ref = new \ReflectionClass($plugineventname);
if (!$ref->isAbstract() && $plugintype . '_' . $plugin !== 'logstore_legacy') {
if (!$ref->isAbstract()) {
$noncorepluginlist = self::format_data($noncorepluginlist, $plugineventname);
}
} else {
+15 -39
View File
@@ -274,12 +274,7 @@ class report_log_table_log extends table_sql {
*/
public function col_eventname($event) {
// Event name.
if ($this->filterparams->logreader instanceof logstore_legacy\log\store) {
// Hack for support of logstore_legacy.
$eventname = $event->eventname;
} else {
$eventname = $event->get_name();
}
$eventname = $event->get_name();
// Only encode as an action link if we're not downloading.
if (($url = $event->get_url()) && empty($this->download)) {
$eventname = $this->action_link($url, $eventname, 'action');
@@ -370,17 +365,7 @@ class report_log_table_log extends table_sql {
global $DB;
// In new logs we have a field to pick, and in legacy try get this from action.
if ($this->filterparams->logreader instanceof logstore_legacy\log\store) {
$action = $this->get_legacy_crud_action($this->filterparams->action);
$firstletter = substr($action, 0, 1);
if ($firstletter == '-') {
$sql = $DB->sql_like('action', ':action', false, true, true);
$params['action'] = '%'.substr($action, 1).'%';
} else {
$sql = $DB->sql_like('action', ':action', false);
$params['action'] = '%'.$action.'%';
}
} else if (!empty($this->filterparams->action)) {
if (!empty($this->filterparams->action)) {
list($sql, $params) = $DB->get_in_or_equal(str_split($this->filterparams->action),
SQL_PARAMS_NAMED, 'crud');
$sql = "crud " . $sql;
@@ -402,16 +387,10 @@ class report_log_table_log extends table_sql {
$joins = array();
$params = array();
if ($this->filterparams->logreader instanceof logstore_legacy\log\store) {
// The legacy store doesn't support context level.
$joins[] = "cmid = :cmid";
$params['cmid'] = $this->filterparams->modid;
} else {
$joins[] = "contextinstanceid = :contextinstanceid";
$joins[] = "contextlevel = :contextmodule";
$params['contextinstanceid'] = $this->filterparams->modid;
$params['contextmodule'] = CONTEXT_MODULE;
}
$joins[] = "contextinstanceid = :contextinstanceid";
$joins[] = "contextlevel = :contextmodule";
$params['contextinstanceid'] = $this->filterparams->modid;
$params['contextmodule'] = CONTEXT_MODULE;
$sql = implode(' AND ', $joins);
return array($sql, $params);
@@ -430,8 +409,7 @@ class report_log_table_log extends table_sql {
$params = array();
// If we filter by userid and module id we also need to filter by crud and edulevel to ensure DB index is engaged.
$useextendeddbindex = !($this->filterparams->logreader instanceof logstore_legacy\log\store)
&& !empty($this->filterparams->userid) && !empty($this->filterparams->modid);
$useextendeddbindex = !empty($this->filterparams->userid) && !empty($this->filterparams->modid);
$groupid = 0;
if (!empty($this->filterparams->courseid) && $this->filterparams->courseid != SITEID) {
@@ -503,16 +481,14 @@ class report_log_table_log extends table_sql {
}
}
if (!($this->filterparams->logreader instanceof logstore_legacy\log\store)) {
// Filter out anonymous actions, this is N/A for legacy log because it never stores them.
if ($this->filterparams->modid) {
$context = context_module::instance($this->filterparams->modid);
} else {
$context = context_course::instance($this->filterparams->courseid);
}
if (!has_capability('moodle/site:viewanonymousevents', $context)) {
$joins[] = "anonymous = 0";
}
// Filter out anonymous actions, this is N/A for legacy log because it never stores them.
if ($this->filterparams->modid) {
$context = context_module::instance($this->filterparams->modid);
} else {
$context = context_course::instance($this->filterparams->courseid);
}
if (!has_capability('moodle/site:viewanonymousevents', $context)) {
$joins[] = "anonymous = 0";
}
$selector = implode(' AND ', $joins);
-5
View File
@@ -94,11 +94,6 @@ if (($edulevel != -1)) {
if ($origin !== '') {
$params['origin'] = $origin;
}
// Legacy store hack, as edulevel is not supported.
if ($logreader == 'logstore_legacy') {
$params['edulevel'] = -1;
$edulevel = -1;
}
$url = new moodle_url("/report/log/index.php", $params);
$PAGE->set_url('/report/log/index.php', array('id' => $id));
+11 -27
View File
@@ -59,7 +59,7 @@ function report_log_print_graph($course, $user, $typeormode, $date=0, $logreader
$reader = $readers[$logreader];
}
// If reader is not a sql_internal_table_reader and not legacy store then don't show graph.
if (!($reader instanceof \core\log\sql_internal_table_reader) && !($reader instanceof logstore_legacy\log\store)) {
if (!($reader instanceof \core\log\sql_internal_table_reader)) {
return array();
}
$coursecontext = context_course::instance($course->id);
@@ -114,23 +114,15 @@ function report_log_usercourse($userid, $courseid, $coursestart, $logreader = ''
}
// If reader is not a sql_internal_table_reader and not legacy store then return.
if (!($reader instanceof \core\log\sql_internal_table_reader) && !($reader instanceof logstore_legacy\log\store)) {
if (!($reader instanceof \core\log\sql_internal_table_reader)) {
return array();
}
$coursestart = (int)$coursestart; // Note: unfortunately pg complains if you use name parameter or column alias in GROUP BY.
if ($reader instanceof logstore_legacy\log\store) {
$logtable = 'log';
$timefield = 'time';
$coursefield = 'course';
// Anonymous actions are never logged in legacy log.
$nonanonymous = '';
} else {
$logtable = $reader->get_internal_log_table_name();
$timefield = 'timecreated';
$coursefield = 'courseid';
$nonanonymous = 'AND anonymous = 0';
}
$logtable = $reader->get_internal_log_table_name();
$timefield = 'timecreated';
$coursefield = 'courseid';
$nonanonymous = 'AND anonymous = 0';
$params = array();
$courseselect = '';
@@ -166,24 +158,16 @@ function report_log_userday($userid, $courseid, $daystart, $logreader = '') {
}
// If reader is not a sql_internal_table_reader and not legacy store then return.
if (!($reader instanceof \core\log\sql_internal_table_reader) && !($reader instanceof logstore_legacy\log\store)) {
if (!($reader instanceof \core\log\sql_internal_table_reader)) {
return array();
}
$daystart = (int)$daystart; // Note: unfortunately pg complains if you use name parameter or column alias in GROUP BY.
if ($reader instanceof logstore_legacy\log\store) {
$logtable = 'log';
$timefield = 'time';
$coursefield = 'course';
// Anonymous actions are never logged in legacy log.
$nonanonymous = '';
} else {
$logtable = $reader->get_internal_log_table_name();
$timefield = 'timecreated';
$coursefield = 'courseid';
$nonanonymous = 'AND anonymous = 0';
}
$logtable = $reader->get_internal_log_table_name();
$timefield = 'timecreated';
$coursefield = 'courseid';
$nonanonymous = 'AND anonymous = 0';
$params = array('userid' => $userid);
$courseselect = '';
-1
View File
@@ -67,7 +67,6 @@ class lib_test extends \advanced_testcase {
$supportedstores = array(
'logstore_database' => '\logstore_database\log\store',
'logstore_legacy' => '\logstore_legacy\log\store',
'logstore_standard' => '\logstore_standard\log\store'
);
+1 -7
View File
@@ -230,13 +230,7 @@ class report_loglive_table_log extends table_sql {
* @return string HTML for the event name column
*/
public function col_eventname($event) {
// Event name.
if ($this->filterparams->logreader instanceof logstore_legacy\log\store) {
// Hack for support of logstore_legacy.
$eventname = $event->eventname;
} else {
$eventname = $event->get_name();
}
$eventname = $event->get_name();
if ($url = $event->get_url()) {
$eventname = $this->action_link($url, $eventname, 'action');
}
-2
View File
@@ -42,8 +42,6 @@ class lib_test extends \advanced_testcase {
$allstores = \core_component::get_plugin_list_with_class('logstore', 'log\store');
$supportedstores = array(
'logstore_database' => '\logstore_legacy\log\database',
'logstore_legacy' => '\logstore_legacy\log\store',
'logstore_standard' => '\logstore_standard\log\store'
);
+1 -1
View File
@@ -119,7 +119,7 @@ function report_outline_page_type_list($pagetype, $parentcontext, $currentcontex
* @return bool returns true if the store is supported by the report, false otherwise.
*/
function report_outline_supports_logstore($instance) {
if ($instance instanceof \core\log\sql_internal_table_reader || $instance instanceof \logstore_legacy\log\store) {
if ($instance instanceof \core\log\sql_internal_table_reader) {
return true;
}
return false;
-5
View File
@@ -82,11 +82,6 @@ function report_outline_get_common_log_variables() {
// Get preferred reader.
if (!empty($readers)) {
foreach ($readers as $readerpluginname => $reader) {
// If legacy reader is preferred reader.
if ($readerpluginname == 'logstore_legacy') {
$uselegacyreader = true;
}
// If sql_internal_table_reader is preferred reader.
if ($reader instanceof \core\log\sql_internal_table_reader) {
$useinternalreader = true;
@@ -24,24 +24,6 @@ Feature: View an outline report
| book | Book name | | C1 | book1 |
When I am on the "Course 1" course page logged in as admin
Scenario: View the outline report when only the legacy log reader is enabled
Given I navigate to "Plugins > Logging > Manage log stores" in site administration
And I click on "Enable" "link" in the "Legacy log" "table_row"
And I click on "Disable" "link" in the "Standard log" "table_row"
And the following config values are set as admin:
| loglegacy | 1 | logstore_legacy |
And I am on the "Course 1" course page logged in as student1
And I follow "Forum name"
And I am on "Course 1" course homepage
And I follow "Book name"
And I am on the "Course 1" course page logged in as student2
And I follow "Book name"
And I am on the "Course 1" course page logged in as teacher1
When I navigate to "Reports" in current page administration
And I click on "Activity report" "link"
Then I should see "2 views by 2 users" in the "Book name" "table_row"
And I should see "1 views by 1 users" in the "Forum name" "table_row"
Scenario: View the outline report when only the standard log reader is enabled
Given I navigate to "Plugins > Logging > Manage log stores" in site administration
And "Enable" "link" should exist in the "Legacy log" "table_row"
-30
View File
@@ -24,36 +24,6 @@ Feature: View the user page for the outline report
| url | URL name | URL description | C1 | folder1 | http://www.google.com |
When I log in as "admin"
Scenario: View the user page when only the legacy log reader is enabled
Given I navigate to "Plugins > Logging > Manage log stores" in site administration
And I click on "Enable" "link" in the "Legacy log" "table_row"
And I click on "Disable" "link" in the "Standard log" "table_row"
And the following config values are set as admin:
| loglegacy | 1 | logstore_legacy |
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
# We want to view this multiple times, to make sure the count is working.
And I follow "Folder name"
And I reload the page
And I reload the page
And I reload the page
# We want to view this multiple times, to make sure the count is working.
And I am on "Course 1" course homepage
And I follow "URL name"
And I reload the page
And I reload the page
And I follow "Profile" in the user menu
And I click on "Course 1" "link" in the "region-main" "region"
When I follow "Outline report"
Then I should see "4 views" in the "Folder name" "table_row"
And I should see "3 views" in the "URL name" "table_row"
And I follow "Profile" in the user menu
And I click on "Course 1" "link" in the "region-main" "region"
And I follow "Complete report"
And I should see "4 views"
And I should see "3 views"
Scenario: View the user page when only the standard log reader is enabled
Given I navigate to "Plugins > Logging > Manage log stores" in site administration
And "Enable" "link" should exist in the "Legacy log" "table_row"
-1
View File
@@ -79,7 +79,6 @@ class lib_test extends \advanced_testcase {
$allstores = \core_component::get_plugin_list_with_class('logstore', 'log\store');
$supportedstores = array(
'logstore_legacy' => '\logstore_legacy\log\store',
'logstore_standard' => '\logstore_standard\log\store'
);
+1 -1
View File
@@ -65,7 +65,7 @@ function report_participation_page_type_list($pagetype, $parentcontext, $current
* @return bool returns true if the store is supported by the report, false otherwise.
*/
function report_participation_supports_logstore($instance) {
if ($instance instanceof \core\log\sql_internal_table_reader || $instance instanceof \logstore_legacy\log\store) {
if ($instance instanceof \core\log\sql_internal_table_reader) {
return true;
}
return false;
-5
View File
@@ -38,11 +38,6 @@ function report_participation_get_log_table_name() {
// Get preferred reader.
if (!empty($readers)) {
foreach ($readers as $readerpluginname => $reader) {
// If legacy reader is preferred reader.
if ($readerpluginname == 'logstore_legacy') {
break;
}
// If sql_internal_table_reader is preferred reader.
if ($reader instanceof \core\log\sql_internal_table_reader) {
$logtable = $reader->get_internal_log_table_name();
@@ -26,25 +26,6 @@ Feature: In a participation report, admin can filter student actions
| title | Test chapter |
| content | Test chapter content |
@javascript
Scenario: Filter participation report when only legacy log reader is enabled
Given I log in as "admin"
And I navigate to "Plugins > Logging > Manage log stores" in site administration
And I click on "Disable" "link" in the "Standard log" "table_row"
And I click on "Enable" "link" in the "Legacy log" "table_row"
And the following config values are set as admin:
| loglegacy | 1 | logstore_legacy |
And I am on the "Test book name" "book activity" page logged in as student1
When I am on the "Course 1" course page logged in as admin
When I navigate to "Reports" in current page administration
And I click on "Course participation" "link"
And I set the field "instanceid" to "Test book name"
And I set the field "roleid" to "Student"
And I press "Go"
Then I should see "Yes (1)"
@javascript
Scenario: Filter participation report when standard log reader is enabled later
Given I log in as "admin"
-1
View File
@@ -42,7 +42,6 @@ class lib_test extends \advanced_testcase {
$allstores = \core_component::get_plugin_list_with_class('logstore', 'log\store');
$supportedstores = array(
'logstore_legacy' => '\logstore_legacy\log\store',
'logstore_standard' => '\logstore_standard\log\store'
);
+1 -1
View File
@@ -126,7 +126,7 @@ function report_stats_page_type_list($pagetype, $parentcontext, $currentcontext)
* @return bool returns true if the store is supported by the report, false otherwise.
*/
function report_stats_supports_logstore($instance) {
if ($instance instanceof \core\log\sql_internal_table_reader || $instance instanceof \logstore_legacy\log\store) {
if ($instance instanceof \core\log\sql_internal_table_reader) {
return true;
}
return false;
-1
View File
@@ -64,7 +64,6 @@ class lib_test extends \advanced_testcase {
$allstores = \core_component::get_plugin_list_with_class('logstore', 'log\store');
$supportedstores = array(
'logstore_legacy' => '\logstore_legacy\log\store',
'logstore_standard' => '\logstore_standard\log\store'
);