From dc0650055951a9312b4a644b598bc7dfa57cf3bf Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 17 Feb 2014 14:25:18 +0800 Subject: [PATCH 1/4] MDL-42890 tool_log Default legacy reader should handle CRUD queries --- .../log/store/legacy/classes/log/store.php | 83 ++++++++++++++++++- .../log/store/legacy/tests/fixtures/store.php | 41 +++++++++ .../log/store/legacy/tests/store_test.php | 55 ++++++++++++ 3 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 admin/tool/log/store/legacy/tests/fixtures/store.php diff --git a/admin/tool/log/store/legacy/classes/log/store.php b/admin/tool/log/store/legacy/classes/log/store.php index d69851a3900..ab8b2f712e8 100644 --- a/admin/tool/log/store/legacy/classes/log/store.php +++ b/admin/tool/log/store/legacy/classes/log/store.php @@ -42,6 +42,9 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader { 'origin' => 'ip' ); + /** @var string Regex to replace the crud params */ + const CRUD_REGEX = "/(crud).*?(<>|=|!=).*?'(.*?)'/s"; + public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) { global $DB; @@ -54,7 +57,7 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader { unset($params[$from]); } } - + $selectwhere = preg_replace_callback(self::CRUD_REGEX, 'self::replace_crud', $selectwhere); $events = array(); $records = array(); @@ -82,6 +85,7 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader { unset($params[$from]); } } + $selectwhere = preg_replace_callback(self::CRUD_REGEX, 'self::replace_crud', $selectwhere); try { return $DB->count_records_select('log', $selectwhere, $params); @@ -209,4 +213,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 can hard code LIKE here because we are not worried about case sensitivity and we don't want this to be faster. + 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; + } } diff --git a/admin/tool/log/store/legacy/tests/fixtures/store.php b/admin/tool/log/store/legacy/tests/fixtures/store.php new file mode 100644 index 00000000000..e588f2cf586 --- /dev/null +++ b/admin/tool/log/store/legacy/tests/fixtures/store.php @@ -0,0 +1,41 @@ +. + +/** + * Fixtures for legacy logging testing. + * + * @package logstore_legacy + * @copyright 2014 onwards Ankit Agarwal + * @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 array $match matched string for the passed pattern + * + * @return string The sql string to use instead of original + */ + public static function replace_crud($match) { + return parent::replace_crud($match); + } +} diff --git a/admin/tool/log/store/legacy/tests/store_test.php b/admin/tool/log/store/legacy/tests/store_test.php index 2a1a5fd0ca4..649b0e6e109 100644 --- a/admin/tool/log/store/legacy/tests/store_test.php +++ b/admin/tool/log/store/legacy/tests/store_test.php @@ -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,58 @@ class logstore_legacy_store_testcase extends advanced_testcase { set_config('loglegacy', 0, 'logstore_legacy'); get_log_manager(true); } + + /** + * Test replace_crud + */ + public function test_replace_crud() { + + $crudregex = logstore_legacy\test\unittest_logstore_legacy::CRUD_REGEX; + + $selectwhere = "edulevel = 0"; + $updatewhere = preg_replace_callback($crudregex, + 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); + $this->assertEquals($selectwhere, $updatewhere); + + $selectwhere = "edulevel = 0 and crud = 'u'"; + $updatewhere = preg_replace_callback($crudregex, + 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); + $this->assertEquals("edulevel = 0 and action LIKE '%update%'", $updatewhere); + + $selectwhere = "edulevel = 0 and crud != 'u'"; + $updatewhere = preg_replace_callback($crudregex, + 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); + $this->assertEquals("edulevel = 0 and action NOT LIKE '%update%'", $updatewhere); + + $selectwhere = "edulevel = 0 and crud <> 'u'"; + $updatewhere = preg_replace_callback($crudregex, + 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); + $this->assertEquals("edulevel = 0 and action NOT LIKE '%update%'", $updatewhere); + + $selectwhere = "edulevel = 0 and crud = 'r'"; + $updatewhere = preg_replace_callback($crudregex, + 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); + $this->assertEquals("edulevel = 0 and action LIKE '%view%' OR action LIKE '%report%'", $updatewhere); + + $selectwhere = "edulevel = 0 and crud != 'r'"; + $updatewhere = preg_replace_callback($crudregex, + 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); + $this->assertEquals("edulevel = 0 and action NOT LIKE '%view%' AND action NOT LIKE '%report%'", $updatewhere); + + $selectwhere = "edulevel = 0 and crud <> 'r'"; + $updatewhere = preg_replace_callback($crudregex, + 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); + $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'"; + $updatewhere = preg_replace_callback($crudregex, + 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); + $this->assertNotEquals("edulevel = 0 and action NOT LIKE '%update%'", $updatewhere); + + $selectwhere = "edulevel = 0 and crud = 'u' OR crud != 'r' or crud <> 'd'"; + $updatewhere = preg_replace_callback($crudregex, + 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); + $this->assertEquals("edulevel = 0 and action LIKE '%update%' OR action NOT LIKE '%view%' AND action NOT LIKE '%report%' or action NOT LIKE '%delete%'", $updatewhere); + } } From 2523979821a4afdb7fa3a3b7dce766699405ed35 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Mon, 17 Feb 2014 14:33:00 +0800 Subject: [PATCH 2/4] MDL-42890 backup: Remove usage of log table in backup cron helper --- .../log/store/legacy/classes/log/store.php | 2 +- .../util/helper/backup_cron_helper.class.php | 36 ++++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/admin/tool/log/store/legacy/classes/log/store.php b/admin/tool/log/store/legacy/classes/log/store.php index ab8b2f712e8..e46dd502568 100644 --- a/admin/tool/log/store/legacy/classes/log/store.php +++ b/admin/tool/log/store/legacy/classes/log/store.php @@ -226,7 +226,7 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader { $return = ''; unset($match[0]); // The first entry is the whole string. foreach ($match as $m) { - // We can hard code LIKE here because we are not worried about case sensitivity and we don't want this to be faster. + // 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'; diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php index 6e13b4281d0..b964b67f015 100644 --- a/backup/util/helper/backup_cron_helper.class.php +++ b/backup/util/helper/backup_cron_helper.class.php @@ -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; + } } From 536c0865efcf0cf3412ad443d2829139d67092df Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Thu, 27 Feb 2014 12:12:54 +0800 Subject: [PATCH 3/4] MDL-42892 logging: Remove usage of logtable from can_delete_course --- .../log/store/legacy/classes/log/store.php | 24 +++++++++++++++++++ .../log/store/legacy/tests/fixtures/store.php | 12 ++++++++++ .../log/store/legacy/tests/store_test.php | 15 ++++++++++++ course/lib.php | 22 +++++++++++++---- 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/admin/tool/log/store/legacy/classes/log/store.php b/admin/tool/log/store/legacy/classes/log/store.php index e46dd502568..058fda13d7d 100644 --- a/admin/tool/log/store/legacy/classes/log/store.php +++ b/admin/tool/log/store/legacy/classes/log/store.php @@ -44,10 +44,31 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader { /** @var string Regex to replace the crud params */ const CRUD_REGEX = "/(crud).*?(<>|=|!=).*?'(.*?)'/s"; + /** + * This method contains hacks required for Moodle core to make legacy store compatible with other sql_select_reader based + * queries. + * + * @param string $select Select statment + * @param array $params params for the sql + * + * @return array returns an array containing the sql predicate and an array of params. + */ + protected static function replace_sql_hacks($select, array $params) { + if ($select == "userid = :userid AND courseid = :courseid AND eventname = :eventname AND timecreated > :since") { + $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); + } + + return array($select, $params); + } public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) { global $DB; + // Replace the query with hardcoded hacks required for core. + list($selectwhere, $params) = self::replace_sql_hacks($selectwhere, $params); + // Replace db field names to make it compatible with legacy log. foreach ($this->standardtolegacyfields as $from => $to) { $selectwhere = str_replace($from, $to, $selectwhere); @@ -77,6 +98,9 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader { public function get_events_select_count($selectwhere, array $params) { global $DB; + // Replace the query with hardcoded hacks required for core. + list($selectwhere, $params) = self::replace_sql_hacks($selectwhere, $params); + // Replace db field names to make it compatible with legacy log. foreach ($this->standardtolegacyfields as $from => $to) { $selectwhere = str_replace($from, $to, $selectwhere); diff --git a/admin/tool/log/store/legacy/tests/fixtures/store.php b/admin/tool/log/store/legacy/tests/fixtures/store.php index e588f2cf586..73b8fdd13b7 100644 --- a/admin/tool/log/store/legacy/tests/fixtures/store.php +++ b/admin/tool/log/store/legacy/tests/fixtures/store.php @@ -38,4 +38,16 @@ class unittest_logstore_legacy extends \logstore_legacy\log\store { public static function replace_crud($match) { return parent::replace_crud($match); } + + /** + * Wrapper to make protected method accessible during testing. + * + * @param string $select sql predicate. + * @param array $params sql params. + * + * @return array returns array of sql predicate and params. + */ + public static function replace_sql_hack($select, array $params) { + return parent::replace_sql_hacks($select, $params); + } } diff --git a/admin/tool/log/store/legacy/tests/store_test.php b/admin/tool/log/store/legacy/tests/store_test.php index 649b0e6e109..3c59ad214e4 100644 --- a/admin/tool/log/store/legacy/tests/store_test.php +++ b/admin/tool/log/store/legacy/tests/store_test.php @@ -214,5 +214,20 @@ class logstore_legacy_store_testcase extends advanced_testcase { $updatewhere = preg_replace_callback($crudregex, 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); $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 replace_sql_hacks() + */ + public function test_replace_sql_hacks() { + $select = "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_hack($select, $params); + $this->assertEquals($replaceselect, $expectedselect); + $this->assertEquals($replaceparams, $expectedparams); } } diff --git a/course/lib.php b/course/lib.php index 973537c4243..562ac03de9e 100644 --- a/course/lib.php +++ b/course/lib.php @@ -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); } /** From e1b2a0b4ef92ae8225f7d3f219bbf43769f41927 Mon Sep 17 00:00:00 2001 From: Ankit Agarwal Date: Tue, 18 Mar 2014 16:04:09 +0800 Subject: [PATCH 4/4] MDL-42892 logging: Refactor logstore_legacy to group all legacy related changes together --- .../log/store/legacy/classes/log/store.php | 61 ++++---- .../log/store/legacy/tests/fixtures/store.php | 18 +-- .../log/store/legacy/tests/store_test.php | 132 ++++++++++-------- 3 files changed, 107 insertions(+), 104 deletions(-) diff --git a/admin/tool/log/store/legacy/classes/log/store.php b/admin/tool/log/store/legacy/classes/log/store.php index 058fda13d7d..6f6df21c8e3 100644 --- a/admin/tool/log/store/legacy/classes/log/store.php +++ b/admin/tool/log/store/legacy/classes/log/store.php @@ -35,7 +35,7 @@ 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', @@ -44,41 +44,50 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader { /** @var string Regex to replace the crud params */ const CRUD_REGEX = "/(crud).*?(<>|=|!=).*?'(.*?)'/s"; + /** - * This method contains hacks required for Moodle core to make legacy store compatible with other sql_select_reader based + * This method contains mapping required for Moodle core to make legacy store compatible with other sql_select_reader based * queries. * - * @param string $select Select statment + * @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 and an array of params. + * @return array returns an array containing the sql predicate, an array of params and sorting parameter. */ - protected static function replace_sql_hacks($select, array $params) { - if ($select == "userid = :userid AND courseid = :courseid AND eventname = :eventname AND timecreated > :since") { + 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); + return array($replace, $params, $sort); } - return array($select, $params); - } - - public function get_events_select($selectwhere, array $params, $sort, $limitfrom, $limitnum) { - global $DB; - - // Replace the query with hardcoded hacks required for core. - list($selectwhere, $params) = self::replace_sql_hacks($selectwhere, $params); - // 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]); } } - $selectwhere = preg_replace_callback(self::CRUD_REGEX, 'self::replace_crud', $selectwhere); + + // 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(); @@ -98,18 +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 the query with hardcoded hacks required for core. - list($selectwhere, $params) = self::replace_sql_hacks($selectwhere, $params); - - // 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]); - } - } - $selectwhere = preg_replace_callback(self::CRUD_REGEX, 'self::replace_crud', $selectwhere); + // 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); diff --git a/admin/tool/log/store/legacy/tests/fixtures/store.php b/admin/tool/log/store/legacy/tests/fixtures/store.php index 73b8fdd13b7..f8fe163ca01 100644 --- a/admin/tool/log/store/legacy/tests/fixtures/store.php +++ b/admin/tool/log/store/legacy/tests/fixtures/store.php @@ -28,26 +28,16 @@ defined('MOODLE_INTERNAL') || die(); class unittest_logstore_legacy extends \logstore_legacy\log\store { - /** - * Wrapper to make protected method accessible during testing. - * - * @param array $match matched string for the passed pattern - * - * @return string The sql string to use instead of original - */ - public static function replace_crud($match) { - return parent::replace_crud($match); - } - /** * 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 and params. + * @return array returns array of sql predicate, params and sorting criteria. */ - public static function replace_sql_hack($select, array $params) { - return parent::replace_sql_hacks($select, $params); + public static function replace_sql_legacy($select, array $params, $sort = '') { + return parent::replace_sql_legacy($select, $params, $sort); } } diff --git a/admin/tool/log/store/legacy/tests/store_test.php b/admin/tool/log/store/legacy/tests/store_test.php index 3c59ad214e4..c99f017ed61 100644 --- a/admin/tool/log/store/legacy/tests/store_test.php +++ b/admin/tool/log/store/legacy/tests/store_test.php @@ -163,71 +163,85 @@ class logstore_legacy_store_testcase extends advanced_testcase { } /** - * Test replace_crud + * Test replace_sql_legacy() */ - public function test_replace_crud() { - - $crudregex = logstore_legacy\test\unittest_logstore_legacy::CRUD_REGEX; - - $selectwhere = "edulevel = 0"; - $updatewhere = preg_replace_callback($crudregex, - 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); - $this->assertEquals($selectwhere, $updatewhere); - - $selectwhere = "edulevel = 0 and crud = 'u'"; - $updatewhere = preg_replace_callback($crudregex, - 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); - $this->assertEquals("edulevel = 0 and action LIKE '%update%'", $updatewhere); - - $selectwhere = "edulevel = 0 and crud != 'u'"; - $updatewhere = preg_replace_callback($crudregex, - 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); - $this->assertEquals("edulevel = 0 and action NOT LIKE '%update%'", $updatewhere); - - $selectwhere = "edulevel = 0 and crud <> 'u'"; - $updatewhere = preg_replace_callback($crudregex, - 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); - $this->assertEquals("edulevel = 0 and action NOT LIKE '%update%'", $updatewhere); - - $selectwhere = "edulevel = 0 and crud = 'r'"; - $updatewhere = preg_replace_callback($crudregex, - 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); - $this->assertEquals("edulevel = 0 and action LIKE '%view%' OR action LIKE '%report%'", $updatewhere); - - $selectwhere = "edulevel = 0 and crud != 'r'"; - $updatewhere = preg_replace_callback($crudregex, - 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); - $this->assertEquals("edulevel = 0 and action NOT LIKE '%view%' AND action NOT LIKE '%report%'", $updatewhere); - - $selectwhere = "edulevel = 0 and crud <> 'r'"; - $updatewhere = preg_replace_callback($crudregex, - 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); - $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'"; - $updatewhere = preg_replace_callback($crudregex, - 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); - $this->assertNotEquals("edulevel = 0 and action NOT LIKE '%update%'", $updatewhere); - - $selectwhere = "edulevel = 0 and crud = 'u' OR crud != 'r' or crud <> 'd'"; - $updatewhere = preg_replace_callback($crudregex, - 'logstore_legacy\test\unittest_logstore_legacy::replace_crud', $selectwhere); - $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 replace_sql_hacks() - */ - public function test_replace_sql_hacks() { - $select = "userid = :userid AND courseid = :courseid AND eventname = :eventname AND timecreated > :since"; + 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_hack($select, $params); + 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); } }