mirror of
https://github.com/moodle/moodle.git
synced 2025-04-20 07:56:06 +02:00
Merge branch 'MDL-42892-master_42890' of git://github.com/ankitagarwal/moodle
This commit is contained in:
commit
efd727063f
@ -35,26 +35,59 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader {
|
||||
}
|
||||
|
||||
/** @var array list of db fields which needs to be replaced for legacy log query */
|
||||
protected $standardtolegacyfields = array(
|
||||
protected static $standardtolegacyfields = array(
|
||||
'timecreated' => 'time',
|
||||
'courseid' => 'course',
|
||||
'contextinstanceid' => 'cmid',
|
||||
'origin' => 'ip'
|
||||
);
|
||||
|
||||
public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
|
||||
global $DB;
|
||||
/** @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_select_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 ($this->standardtolegacyfields as $from => $to) {
|
||||
foreach (self::$standardtolegacyfields as $from => $to) {
|
||||
$selectwhere = str_replace($from, $to, $selectwhere);
|
||||
$sort = str_replace($from, $to, $sort);
|
||||
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::replace_crud', $selectwhere);
|
||||
|
||||
return array($selectwhere, $params, $sort);
|
||||
}
|
||||
|
||||
public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) {
|
||||
global $DB;
|
||||
|
||||
// Replace the query with hardcoded mappings required for core.
|
||||
list($selectwhere, $params, $sort) = self::replace_sql_legacy($selectwhere, $params, $sort);
|
||||
|
||||
$events = array();
|
||||
$records = array();
|
||||
|
||||
@ -74,14 +107,8 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader {
|
||||
public function get_events_select_count($selectwhere, array $params) {
|
||||
global $DB;
|
||||
|
||||
// Replace db field names to make it compatible with legacy log.
|
||||
foreach ($this->standardtolegacyfields as $from => $to) {
|
||||
$selectwhere = str_replace($from, $to, $selectwhere);
|
||||
if (isset($params[$from])) {
|
||||
$params[$to] = $params[$from];
|
||||
unset($params[$from]);
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
@ -198,4 +225,81 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
43
admin/tool/log/store/legacy/tests/fixtures/store.php
vendored
Normal file
43
admin/tool/log/store/legacy/tests/fixtures/store.php
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
<?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 <ankit.agrr@gmail.com>
|
||||
* @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);
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/fixtures/event.php');
|
||||
require_once(__DIR__ . '/fixtures/store.php');
|
||||
|
||||
class logstore_legacy_store_testcase extends advanced_testcase {
|
||||
public function test_log_writing() {
|
||||
@ -160,4 +161,87 @@ class logstore_legacy_store_testcase extends advanced_testcase {
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -153,14 +153,9 @@ abstract class backup_cron_automated_helper {
|
||||
// If config backup_auto_skip_modif_days is set to true, skip courses
|
||||
// that have not been modified since the number of days defined.
|
||||
if ($shouldrunnow && !$skipped && $lastbackupwassuccessful && $config->backup_auto_skip_modif_days) {
|
||||
$sqlwhere = "course=:courseid AND time>:time AND ".$DB->sql_like('action', ':action', false, true, true);
|
||||
$timenotmodifsincedays = $now - ($config->backup_auto_skip_modif_days * DAYSECS);
|
||||
// Check log if there were any modifications to the course content.
|
||||
$params = array('courseid' => $course->id,
|
||||
'time' => $timenotmodifsincedays,
|
||||
'action' => '%view%');
|
||||
$logexists = $DB->record_exists_select('log', $sqlwhere, $params);
|
||||
|
||||
$logexists = self::is_course_modified($course->id, $timenotmodifsincedays);
|
||||
$skipped = ($course->timemodified <= $timenotmodifsincedays && !$logexists);
|
||||
$skippedmessage = 'Not modified in the past '.$config->backup_auto_skip_modif_days.' days';
|
||||
}
|
||||
@ -169,12 +164,7 @@ abstract class backup_cron_automated_helper {
|
||||
// that have not been modified since previous backup.
|
||||
if ($shouldrunnow && !$skipped && $lastbackupwassuccessful && $config->backup_auto_skip_modif_prev) {
|
||||
// Check log if there were any modifications to the course content.
|
||||
$sqlwhere = "course=:courseid AND time>:time AND ".$DB->sql_like('action', ':action', false, true, true);
|
||||
$params = array('courseid' => $course->id,
|
||||
'time' => $backupcourse->laststarttime,
|
||||
'action' => '%view%');
|
||||
$logexists = $DB->record_exists_select('log', $sqlwhere, $params);
|
||||
|
||||
$logexists = self::is_course_modified($course->id, $backupcourse->laststarttime);
|
||||
$skipped = ($course->timemodified <= $backupcourse->laststarttime && !$logexists);
|
||||
$skippedmessage = 'Not modified since previous backup';
|
||||
}
|
||||
@ -668,4 +658,26 @@ abstract class backup_cron_automated_helper {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check logs to find out if a course was modified since the given time.
|
||||
*
|
||||
* @param int $courseid course id to check
|
||||
* @param int $since timestamp, from which to check
|
||||
*
|
||||
* @return bool true if the course was modified, false otherwise. This also returns false if no readers are enabled. This is
|
||||
* intentional, since we cannot reliably determine if any modification was made or not.
|
||||
*/
|
||||
protected static function is_course_modified($courseid, $since) {
|
||||
$logmang = get_log_manager();
|
||||
$readers = $logmang->get_readers('core\log\sql_select_reader');
|
||||
$where = "courseid = :courseid and timecreated > :since and crud <> 'r'";
|
||||
$params = array('courseid' => $courseid, 'since' => $since);
|
||||
foreach ($readers as $reader) {
|
||||
if ($reader->get_events_select_count($where, $params)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2353,7 +2353,7 @@ function course_format_ajax_support($format) {
|
||||
* @return boolean
|
||||
*/
|
||||
function can_delete_course($courseid) {
|
||||
global $USER, $DB;
|
||||
global $USER;
|
||||
|
||||
$context = context_course::instance($courseid);
|
||||
|
||||
@ -2367,11 +2367,25 @@ function can_delete_course($courseid) {
|
||||
}
|
||||
|
||||
$since = time() - 60*60*24;
|
||||
$course = get_course($courseid);
|
||||
|
||||
$params = array('userid'=>$USER->id, 'url'=>"view.php?id=$courseid", 'since'=>$since);
|
||||
$select = "module = 'course' AND action = 'new' AND userid = :userid AND url = :url AND time > :since";
|
||||
if ($course->timecreated < $since) {
|
||||
return false; // Return if the course was not created in last 24 hours.
|
||||
}
|
||||
|
||||
return $DB->record_exists_select('log', $select, $params);
|
||||
$logmanger = get_log_manager();
|
||||
$readers = $logmanger->get_readers('\core\log\sql_select_reader');
|
||||
$reader = reset($readers);
|
||||
|
||||
if (empty($reader)) {
|
||||
return false; // No log reader found.
|
||||
}
|
||||
|
||||
// A proper reader.
|
||||
$select = "userid = :userid AND courseid = :courseid AND eventname = :eventname AND timecreated > :since";
|
||||
$params = array('userid' => $USER->id, 'since' => $since, 'courseid' => $course->id, 'eventname' => '\core\event\course_created');
|
||||
|
||||
return (bool)$reader->get_events_select_count($select, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user