���ѧۧݧ�ӧ�� �ާ֧ߧ֧էا֧� - ���֧էѧܧ�ڧ��ӧѧ�� - /home3/cpr76684/public_html/legacy.tar
���ѧ٧ѧ�
db/tasks.php 0000644 00000002227 15152567427 0007010 0 ustar 00 <?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' => '*' ), ); tests/fixtures/event.php 0000644 00000003665 15152567427 0011441 0 ustar 00 <?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'])); } public static function get_legacy_eventname() { return 'test_legacy'; } protected function get_legacy_eventdata() { return array($this->data['courseid'], $this->data['other']['sample']); } protected function get_legacy_logdata() { $cmid = 0; if ($this->contextlevel == CONTEXT_MODULE) { $cmid = $this->contextinstanceid; } return array($this->data['courseid'], 'core_unittest', 'view', 'unittest.php?id=' . $this->data['other']['sample'], 'bbb', $cmid); } } tests/fixtures/store.php 0000644 00000002752 15152567427 0011450 0 ustar 00 <?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); } } tests/privacy/provider_test.php 0000644 00000054265 15152567427 0013017 0 ustar 00 <?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 <fred@branchup.tech> * @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 <fred@branchup.tech> * @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; } } tests/store_test.php 0000644 00000030620 15152567430 0010623 0 ustar 00 <?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')); } } settings.php 0000644 00000004372 15152567430 0007133 0 ustar 00 <?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)); } version.php 0000644 00000002207 15152567430 0006753 0 ustar 00 <?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). classes/privacy/provider.php 0000644 00000022331 15152567430 0012232 0 ustar 00 <?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 <fred@branchup.tech> * @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 <fred@branchup.tech> * @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]; } } classes/log/store.php 0000644 00000041701 15152567430 0010642 0 ustar 00 <?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::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; } } classes/event/legacy_logged.php 0000644 00000003230 15152567430 0012626 0 ustar 00 <?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); } } classes/task/cleanup_task.php 0000644 00000004514 15152567430 0012341 0 ustar 00 <?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"); } } lang/en/logstore_legacy.php 0000644 00000004127 15152567430 0011776 0 ustar 00 <?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';
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | ���֧ߧ֧�ѧ�ڧ� ����ѧߧڧ��: 0 |
proxy
|
phpinfo
|
���ѧ����ۧܧ�