1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Data provider tests. 19 * 20 * @package logstore_database 21 * @category test 22 * @copyright 2018 Frédéric Massart 23 * @author Frédéric Massart <fred@branchup.tech> 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 namespace logstore_database\privacy; 27 28 defined('MOODLE_INTERNAL') || die(); 29 global $CFG; 30 31 use core_privacy\tests\provider_testcase; 32 use core_privacy\local\request\contextlist; 33 use core_privacy\local\request\approved_contextlist; 34 use core_privacy\local\request\transform; 35 use core_privacy\local\request\writer; 36 use logstore_database\privacy\provider; 37 38 require_once (__DIR__ . '/../fixtures/event.php'); 39 40 /** 41 * Data provider testcase class. 42 * 43 * This testcase is almost identical to the logstore_standard testcase, aside from the 44 * initialisation of the relevant logstore obviously. 45 * 46 * @package logstore_database 47 * @category test 48 * @copyright 2018 Frédéric Massart 49 * @author Frédéric Massart <fred@branchup.tech> 50 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 51 */ 52 class provider_test extends provider_testcase { 53 54 public function setUp(): void { 55 global $CFG; 56 $this->resetAfterTest(); 57 $this->preventResetByRollback(); // Logging waits till the transaction gets committed. 58 59 // Fake the settings, we will abuse the standard plugin table here... 60 set_config('dbdriver', $CFG->dblibrary . '/' . $CFG->dbtype, 'logstore_database'); 61 set_config('dbhost', $CFG->dbhost, 'logstore_database'); 62 set_config('dbuser', $CFG->dbuser, 'logstore_database'); 63 set_config('dbpass', $CFG->dbpass, 'logstore_database'); 64 set_config('dbname', $CFG->dbname, 'logstore_database'); 65 set_config('dbtable', $CFG->prefix . 'logstore_standard_log', 'logstore_database'); 66 if (!empty($CFG->dboptions['dbpersist'])) { 67 set_config('dbpersist', 1, 'logstore_database'); 68 } else { 69 set_config('dbpersist', 0, 'logstore_database'); 70 } 71 if (!empty($CFG->dboptions['dbsocket'])) { 72 set_config('dbsocket', $CFG->dboptions['dbsocket'], 'logstore_database'); 73 } else { 74 set_config('dbsocket', '', 'logstore_database'); 75 } 76 if (!empty($CFG->dboptions['dbport'])) { 77 set_config('dbport', $CFG->dboptions['dbport'], 'logstore_database'); 78 } else { 79 set_config('dbport', '', 'logstore_database'); 80 } 81 if (!empty($CFG->dboptions['dbschema'])) { 82 set_config('dbschema', $CFG->dboptions['dbschema'], 'logstore_database'); 83 } else { 84 set_config('dbschema', '', 'logstore_database'); 85 } 86 if (!empty($CFG->dboptions['dbcollation'])) { 87 set_config('dbcollation', $CFG->dboptions['dbcollation'], 'logstore_database'); 88 } else { 89 set_config('dbcollation', '', 'logstore_database'); 90 } 91 if (!empty($CFG->dboptions['dbhandlesoptions'])) { 92 set_config('dbhandlesoptions', $CFG->dboptions['dbhandlesoptions'], 'logstore_database'); 93 } else { 94 set_config('dbhandlesoptions', false, 'logstore_database'); 95 } 96 } 97 98 public function test_get_contexts_for_userid() { 99 $admin = \core_user::get_user(2); 100 $u1 = $this->getDataGenerator()->create_user(); 101 $u2 = $this->getDataGenerator()->create_user(); 102 $u3 = $this->getDataGenerator()->create_user(); 103 104 $c1 = $this->getDataGenerator()->create_course(); 105 $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]); 106 $c2 = $this->getDataGenerator()->create_course(); 107 $cm2 = $this->getDataGenerator()->create_module('url', ['course' => $c2]); 108 109 $sysctx = \context_system::instance(); 110 $c1ctx = \context_course::instance($c1->id); 111 $c2ctx = \context_course::instance($c2->id); 112 $cm1ctx = \context_module::instance($cm1->cmid); 113 $cm2ctx = \context_module::instance($cm2->cmid); 114 115 $this->enable_logging(); 116 $manager = get_log_manager(true); 117 118 // User 1 is the author. 119 $this->setUser($u1); 120 $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), []); 121 $e = \logstore_database\event\unittest_executed::create(['context' => $cm1ctx]); 122 $e->trigger(); 123 $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$cm1ctx]); 124 125 // User 2 is the related user. 126 $this->setUser(0); 127 $this->assert_contextlist_equals($this->get_contextlist_for_user($u2), []); 128 $e = \logstore_database\event\unittest_executed::create(['context' => $cm2ctx, 'relateduserid' => $u2->id]); 129 $e->trigger(); 130 $this->assert_contextlist_equals($this->get_contextlist_for_user($u2), [$cm2ctx]); 131 132 // Admin user is the real user. 133 $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), []); 134 $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), []); 135 $this->setAdminUser(); 136 \core\session\manager::loginas($u3->id, $sysctx); 137 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx]); 138 $e->trigger(); 139 $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), [$sysctx, $c1ctx]); 140 $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx, $c1ctx]); 141 142 // By admin user masquerading u1 related to u3. 143 $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$cm1ctx]); 144 $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx, $c1ctx]); 145 $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), [$sysctx, $c1ctx]); 146 $this->setAdminUser(); 147 \core\session\manager::loginas($u1->id, \context_system::instance()); 148 $e = \logstore_database\event\unittest_executed::create(['context' => $c2ctx, 'relateduserid' => $u3->id]); 149 $e->trigger(); 150 $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$sysctx, $cm1ctx, $c2ctx]); 151 $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx, $c1ctx, $c2ctx]); 152 $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), [$sysctx, $c1ctx, $c2ctx]); 153 } 154 155 /** 156 * Check that user IDs are returned for a given context. 157 */ 158 public function test_add_userids_for_context() { 159 $admin = \core_user::get_user(2); 160 $u1 = $this->getDataGenerator()->create_user(); 161 $u2 = $this->getDataGenerator()->create_user(); 162 $u3 = $this->getDataGenerator()->create_user(); 163 $u4 = $this->getDataGenerator()->create_user(); 164 165 $c1 = $this->getDataGenerator()->create_course(); 166 167 $sysctx = \context_system::instance(); 168 $c1ctx = \context_course::instance($c1->id); 169 170 $this->enable_logging(); 171 $manager = get_log_manager(true); 172 173 $userlist = new \core_privacy\local\request\userlist($sysctx, 'logstore_database'); 174 $userids = $userlist->get_userids(); 175 $this->assertEmpty($userids); 176 provider::add_userids_for_context($userlist); 177 $userids = $userlist->get_userids(); 178 $this->assertEmpty($userids); 179 // User one should be added (userid). 180 $this->setUser($u1); 181 $e = \logstore_database\event\unittest_executed::create(['context' => $sysctx]); 182 $e->trigger(); 183 // User two (userids) and three (relateduserid) should be added. 184 $this->setUser($u2); 185 $e = \logstore_database\event\unittest_executed::create(['context' => $sysctx, 'relateduserid' => $u3->id]); 186 $e->trigger(); 187 // The admin user should be added (realuserid). 188 $this->setAdminUser(); 189 \core\session\manager::loginas($u2->id, \context_system::instance()); 190 $e = \logstore_database\event\unittest_executed::create(['context' => $sysctx]); 191 $e->trigger(); 192 // Set off an event in a different context. User 4 should not be returned below. 193 $this->setUser($u4); 194 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx]); 195 $e->trigger(); 196 197 provider::add_userids_for_context($userlist); 198 $userids = $userlist->get_userids(); 199 $this->assertCount(4, $userids); 200 $expectedresult = [$admin->id, $u1->id, $u2->id, $u3->id]; 201 $this->assertEmpty(array_diff($expectedresult, $userids)); 202 } 203 204 public function test_delete_data_for_user() { 205 global $DB; 206 $u1 = $this->getDataGenerator()->create_user(); 207 $u2 = $this->getDataGenerator()->create_user(); 208 $c1 = $this->getDataGenerator()->create_course(); 209 $c2 = $this->getDataGenerator()->create_course(); 210 $sysctx = \context_system::instance(); 211 $c1ctx = \context_course::instance($c1->id); 212 $c2ctx = \context_course::instance($c2->id); 213 214 $this->enable_logging(); 215 $manager = get_log_manager(true); 216 217 // User 1 is the author. 218 $this->setUser($u1); 219 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx]); 220 $e->trigger(); 221 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx]); 222 $e->trigger(); 223 $e = \logstore_database\event\unittest_executed::create(['context' => $c2ctx]); 224 $e->trigger(); 225 226 // User 2 is the author. 227 $this->setUser($u2); 228 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx]); 229 $e->trigger(); 230 $e = \logstore_database\event\unittest_executed::create(['context' => $c2ctx]); 231 $e->trigger(); 232 233 // Confirm data present. 234 $this->assertTrue($DB->record_exists('logstore_standard_log', ['userid' => $u1->id, 'contextid' => $c1ctx->id])); 235 $this->assertEquals(3, $DB->count_records('logstore_standard_log', ['userid' => $u1->id])); 236 $this->assertEquals(2, $DB->count_records('logstore_standard_log', ['userid' => $u2->id])); 237 238 // Delete all the things! 239 provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_database', [$c1ctx->id])); 240 $this->assertFalse($DB->record_exists('logstore_standard_log', ['userid' => $u1->id, 'contextid' => $c1ctx->id])); 241 $this->assertEquals(1, $DB->count_records('logstore_standard_log', ['userid' => $u1->id])); 242 $this->assertEquals(2, $DB->count_records('logstore_standard_log', ['userid' => $u2->id])); 243 } 244 245 public function test_delete_data_for_all_users_in_context() { 246 global $DB; 247 $u1 = $this->getDataGenerator()->create_user(); 248 $u2 = $this->getDataGenerator()->create_user(); 249 $c1 = $this->getDataGenerator()->create_course(); 250 $c2 = $this->getDataGenerator()->create_course(); 251 $sysctx = \context_system::instance(); 252 $c1ctx = \context_course::instance($c1->id); 253 $c2ctx = \context_course::instance($c2->id); 254 255 $this->enable_logging(); 256 $manager = get_log_manager(true); 257 258 // User 1 is the author. 259 $this->setUser($u1); 260 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx]); 261 $e->trigger(); 262 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx]); 263 $e->trigger(); 264 $e = \logstore_database\event\unittest_executed::create(['context' => $c2ctx]); 265 $e->trigger(); 266 267 // User 2 is the author. 268 $this->setUser($u2); 269 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx]); 270 $e->trigger(); 271 $e = \logstore_database\event\unittest_executed::create(['context' => $c2ctx]); 272 $e->trigger(); 273 274 // Confirm data present. 275 $this->assertTrue($DB->record_exists('logstore_standard_log', ['contextid' => $c1ctx->id])); 276 $this->assertEquals(3, $DB->count_records('logstore_standard_log', ['userid' => $u1->id])); 277 $this->assertEquals(2, $DB->count_records('logstore_standard_log', ['userid' => $u2->id])); 278 279 // Delete all the things! 280 provider::delete_data_for_all_users_in_context($c1ctx); 281 $this->assertFalse($DB->record_exists('logstore_standard_log', ['contextid' => $c1ctx->id])); 282 $this->assertEquals(1, $DB->count_records('logstore_standard_log', ['userid' => $u1->id])); 283 $this->assertEquals(1, $DB->count_records('logstore_standard_log', ['userid' => $u2->id])); 284 } 285 286 /** 287 * Check that data is removed for the listed users in a given context. 288 */ 289 public function test_delete_data_for_userlist() { 290 global $DB; 291 292 $u1 = $this->getDataGenerator()->create_user(); 293 $u2 = $this->getDataGenerator()->create_user(); 294 $u3 = $this->getDataGenerator()->create_user(); 295 $u4 = $this->getDataGenerator()->create_user(); 296 297 $course = $this->getDataGenerator()->create_course(); 298 $sysctx = \context_system::instance(); 299 $c1ctx = \context_course::instance($course->id); 300 301 $this->enable_logging(); 302 $manager = get_log_manager(true); 303 304 $this->setUser($u1); 305 $e = \logstore_database\event\unittest_executed::create(['context' => $sysctx]); 306 $e->trigger(); 307 $this->setUser($u2); 308 $e = \logstore_database\event\unittest_executed::create(['context' => $sysctx]); 309 $e->trigger(); 310 $this->setUser($u3); 311 $e = \logstore_database\event\unittest_executed::create(['context' => $sysctx]); 312 $e->trigger(); 313 $this->setUser($u4); 314 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx]); 315 $e->trigger(); 316 317 // Check that four records were created. 318 $this->assertEquals(4, $DB->count_records('logstore_standard_log')); 319 320 $userlist = new \core_privacy\local\request\approved_userlist($sysctx, 'logstore_database', [$u1->id, $u3->id]); 321 provider::delete_data_for_userlist($userlist); 322 // We should have a record for u2 and u4. 323 $this->assertEquals(2, $DB->count_records('logstore_standard_log')); 324 325 $records = $DB->get_records('logstore_standard_log', ['contextid' => $sysctx->id]); 326 $this->assertCount(1, $records); 327 $currentrecord = array_shift($records); 328 $this->assertEquals($u2->id, $currentrecord->userid); 329 } 330 331 public function test_export_data_for_user() { 332 $admin = \core_user::get_user(2); 333 $u1 = $this->getDataGenerator()->create_user(); 334 $u2 = $this->getDataGenerator()->create_user(); 335 $u3 = $this->getDataGenerator()->create_user(); 336 $u4 = $this->getDataGenerator()->create_user(); 337 $c1 = $this->getDataGenerator()->create_course(); 338 $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]); 339 $c2 = $this->getDataGenerator()->create_course(); 340 $cm2 = $this->getDataGenerator()->create_module('url', ['course' => $c2]); 341 $sysctx = \context_system::instance(); 342 $c1ctx = \context_course::instance($c1->id); 343 $c2ctx = \context_course::instance($c2->id); 344 $cm1ctx = \context_module::instance($cm1->cmid); 345 $cm2ctx = \context_module::instance($cm2->cmid); 346 347 $path = [get_string('privacy:path:logs', 'tool_log'), get_string('pluginname', 'logstore_database')]; 348 $this->enable_logging(); 349 $manager = get_log_manager(true); 350 351 // User 1 is the author. 352 $this->setUser($u1); 353 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx, 'other' => ['i' => 0]]); 354 $e->trigger(); 355 356 // User 2 is related. 357 $this->setUser(0); 358 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx, 'relateduserid' => $u2->id, 359 'other' => ['i' => 1]]); 360 $e->trigger(); 361 362 // Admin user masquerades u3, which is related to u4. 363 $this->setAdminUser(); 364 \core\session\manager::loginas($u3->id, $sysctx); 365 $e = \logstore_database\event\unittest_executed::create(['context' => $c1ctx, 'relateduserid' => $u4->id, 366 'other' => ['i' => 2]]); 367 $e->trigger(); 368 369 // Confirm data present for u1. 370 provider::export_user_data(new approved_contextlist($u1, 'logstore_database', [$c2ctx->id, $c1ctx->id])); 371 $data = writer::with_context($c2ctx)->get_data($path); 372 $this->assertEmpty($data); 373 $data = writer::with_context($c1ctx)->get_data($path); 374 $this->assertCount(1, $data->logs); 375 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']); 376 $this->assertSame(0, $data->logs[0]['other']['i']); 377 378 // Confirm data present for u2. 379 writer::reset(); 380 provider::export_user_data(new approved_contextlist($u2, 'logstore_database', [$c2ctx->id, $c1ctx->id])); 381 $data = writer::with_context($c2ctx)->get_data($path); 382 $this->assertEmpty($data); 383 $data = writer::with_context($c1ctx)->get_data($path); 384 $this->assertCount(1, $data->logs); 385 $this->assertEquals(transform::yesno(false), $data->logs[0]['author_of_the_action_was_you']); 386 $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']); 387 $this->assertSame(1, $data->logs[0]['other']['i']); 388 389 // Confirm data present for u3. 390 writer::reset(); 391 provider::export_user_data(new approved_contextlist($u3, 'logstore_database', [$c2ctx->id, $c1ctx->id])); 392 $data = writer::with_context($c2ctx)->get_data($path); 393 $this->assertEmpty($data); 394 $data = writer::with_context($c1ctx)->get_data($path); 395 $this->assertCount(1, $data->logs); 396 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']); 397 $this->assertEquals(transform::yesno(false), $data->logs[0]['related_user_was_you']); 398 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']); 399 $this->assertEquals(transform::yesno(false), $data->logs[0]['masquerading_user_was_you']); 400 $this->assertSame(2, $data->logs[0]['other']['i']); 401 402 // Confirm data present for u4. 403 writer::reset(); 404 provider::export_user_data(new approved_contextlist($u4, 'logstore_database', [$c2ctx->id, $c1ctx->id])); 405 $data = writer::with_context($c2ctx)->get_data($path); 406 $this->assertEmpty($data); 407 $data = writer::with_context($c1ctx)->get_data($path); 408 $this->assertCount(1, $data->logs); 409 $this->assertEquals(transform::yesno(false), $data->logs[0]['author_of_the_action_was_you']); 410 $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']); 411 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']); 412 $this->assertEquals(transform::yesno(false), $data->logs[0]['masquerading_user_was_you']); 413 $this->assertSame(2, $data->logs[0]['other']['i']); 414 415 // Add anonymous events. 416 $this->setUser($u1); 417 $e = \logstore_database\event\unittest_executed::create(['context' => $c2ctx, 'relateduserid' => $u2->id, 418 'anonymous' => true]); 419 $e->trigger(); 420 $this->setAdminUser(); 421 \core\session\manager::loginas($u3->id, $sysctx); 422 $e = \logstore_database\event\unittest_executed::create(['context' => $c2ctx, 'relateduserid' => $u4->id, 423 'anonymous' => true]); 424 $e->trigger(); 425 426 // Confirm data present for u1. 427 provider::export_user_data(new approved_contextlist($u1, 'logstore_database', [$c2ctx->id])); 428 $data = writer::with_context($c2ctx)->get_data($path); 429 $this->assertCount(1, $data->logs); 430 $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']); 431 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']); 432 433 // Confirm data present for u2. 434 writer::reset(); 435 provider::export_user_data(new approved_contextlist($u2, 'logstore_database', [$c2ctx->id])); 436 $data = writer::with_context($c2ctx)->get_data($path); 437 $this->assertCount(1, $data->logs); 438 $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']); 439 $this->assertArrayNotHasKey('author_of_the_action_was_you', $data->logs[0]); 440 $this->assertArrayNotHasKey('authorid', $data->logs[0]); 441 $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']); 442 443 // Confirm data present for u3. 444 writer::reset(); 445 provider::export_user_data(new approved_contextlist($u3, 'logstore_database', [$c2ctx->id])); 446 $data = writer::with_context($c2ctx)->get_data($path); 447 $this->assertCount(1, $data->logs); 448 $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']); 449 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']); 450 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']); 451 $this->assertArrayNotHasKey('masquerading_user_was_you', $data->logs[0]); 452 $this->assertArrayNotHasKey('masqueradinguserid', $data->logs[0]); 453 454 // Confirm data present for u4. 455 writer::reset(); 456 provider::export_user_data(new approved_contextlist($u4, 'logstore_database', [$c2ctx->id])); 457 $data = writer::with_context($c2ctx)->get_data($path); 458 $this->assertCount(1, $data->logs); 459 $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']); 460 $this->assertArrayNotHasKey('author_of_the_action_was_you', $data->logs[0]); 461 $this->assertArrayNotHasKey('authorid', $data->logs[0]); 462 $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']); 463 $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']); 464 $this->assertArrayNotHasKey('masquerading_user_was_you', $data->logs[0]); 465 $this->assertArrayNotHasKey('masqueradinguserid', $data->logs[0]); 466 } 467 468 /** 469 * Assert the content of a context list. 470 * 471 * @param contextlist $contextlist The collection. 472 * @param array $expected List of expected contexts or IDs. 473 * @return void 474 */ 475 protected function assert_contextlist_equals($contextlist, array $expected) { 476 $expectedids = array_map(function($context) { 477 if (is_object($context)) { 478 return $context->id; 479 } 480 return $context; 481 }, $expected); 482 $contextids = array_map('intval', $contextlist->get_contextids()); 483 sort($contextids); 484 sort($expectedids); 485 $this->assertEquals($expectedids, $contextids); 486 } 487 488 /** 489 * Enable logging. 490 * 491 * @return void 492 */ 493 protected function enable_logging() { 494 set_config('enabled_stores', 'logstore_database', 'tool_log'); 495 set_config('buffersize', 0, 'logstore_database'); 496 set_config('logguests', 1, 'logstore_database'); 497 get_log_manager(true); 498 } 499 500 /** 501 * Get the contextlist for a user. 502 * 503 * @param object $user The user. 504 * @return contextlist 505 */ 506 protected function get_contextlist_for_user($user) { 507 $contextlist = new contextlist(); 508 provider::add_contexts_for_userid($contextlist, $user->id); 509 return $contextlist; 510 } 511 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body