Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   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_standard
  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_standard\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_standard\privacy\provider;
  37  
  38  require_once (__DIR__ . '/../fixtures/event.php');
  39  
  40  /**
  41   * Data provider testcase class.
  42   *
  43   * @package    logstore_standard
  44   * @category   test
  45   * @copyright  2018 Frédéric Massart
  46   * @author     Frédéric Massart <fred@branchup.tech>
  47   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  48   */
  49  class provider_test extends provider_testcase {
  50  
  51      public function setUp(): void {
  52          $this->resetAfterTest();
  53          $this->preventResetByRollback(); // Logging waits till the transaction gets committed.
  54      }
  55  
  56      public function test_get_contexts_for_userid() {
  57          $admin = \core_user::get_user(2);
  58          $u1 = $this->getDataGenerator()->create_user();
  59          $u2 = $this->getDataGenerator()->create_user();
  60          $u3 = $this->getDataGenerator()->create_user();
  61  
  62          $c1 = $this->getDataGenerator()->create_course();
  63          $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
  64          $c2 = $this->getDataGenerator()->create_course();
  65          $cm2 = $this->getDataGenerator()->create_module('url', ['course' => $c2]);
  66  
  67          $sysctx = \context_system::instance();
  68          $c1ctx = \context_course::instance($c1->id);
  69          $c2ctx = \context_course::instance($c2->id);
  70          $cm1ctx = \context_module::instance($cm1->cmid);
  71          $cm2ctx = \context_module::instance($cm2->cmid);
  72  
  73          $this->enable_logging();
  74          $manager = get_log_manager(true);
  75  
  76          // User 1 is the author.
  77          $this->setUser($u1);
  78          $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), []);
  79          $e = \logstore_standard\event\unittest_executed::create(['context' => $cm1ctx]);
  80          $e->trigger();
  81          $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$cm1ctx]);
  82  
  83          // User 2 is the related user.
  84          $this->setUser(0);
  85          $this->assert_contextlist_equals($this->get_contextlist_for_user($u2), []);
  86          $e = \logstore_standard\event\unittest_executed::create(['context' => $cm2ctx, 'relateduserid' => $u2->id]);
  87          $e->trigger();
  88          $this->assert_contextlist_equals($this->get_contextlist_for_user($u2), [$cm2ctx]);
  89  
  90          // Admin user is the real user.
  91          $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), []);
  92          $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), []);
  93          $this->setAdminUser();
  94          \core\session\manager::loginas($u3->id, $sysctx);
  95          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
  96          $e->trigger();
  97          $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), [$sysctx, $c1ctx]);
  98          $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx, $c1ctx]);
  99  
 100          // By admin user masquerading u1 related to u3.
 101          $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$cm1ctx]);
 102          $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx, $c1ctx]);
 103          $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), [$sysctx, $c1ctx]);
 104          $this->setAdminUser();
 105          \core\session\manager::loginas($u1->id, \context_system::instance());
 106          $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx, 'relateduserid' => $u3->id]);
 107          $e->trigger();
 108          $this->assert_contextlist_equals($this->get_contextlist_for_user($u1), [$sysctx, $cm1ctx, $c2ctx]);
 109          $this->assert_contextlist_equals($this->get_contextlist_for_user($u3), [$sysctx, $c1ctx, $c2ctx]);
 110          $this->assert_contextlist_equals($this->get_contextlist_for_user($admin), [$sysctx, $c1ctx, $c2ctx]);
 111      }
 112  
 113      public function test_add_userids_for_context() {
 114          $admin = \core_user::get_user(2);
 115          $u1 = $this->getDataGenerator()->create_user();
 116          $u2 = $this->getDataGenerator()->create_user();
 117          $u3 = $this->getDataGenerator()->create_user();
 118          $u4 = $this->getDataGenerator()->create_user();
 119  
 120          $c1 = $this->getDataGenerator()->create_course();
 121  
 122          $sysctx = \context_system::instance();
 123          $c1ctx = \context_course::instance($c1->id);
 124  
 125          $this->enable_logging();
 126          $manager = get_log_manager(true);
 127  
 128          $userlist = new \core_privacy\local\request\userlist($sysctx, 'logstore_standard_log');
 129          $userids = $userlist->get_userids();
 130          $this->assertEmpty($userids);
 131          provider::add_userids_for_context($userlist);
 132          $userids = $userlist->get_userids();
 133          $this->assertEmpty($userids);
 134          // User one should be added (userid).
 135          $this->setUser($u1);
 136          $e = \logstore_standard\event\unittest_executed::create(['context' => $sysctx]);
 137          $e->trigger();
 138          // User two (userids) and three (relateduserid) should be added.
 139          $this->setUser($u2);
 140          $e = \logstore_standard\event\unittest_executed::create(['context' => $sysctx, 'relateduserid' => $u3->id]);
 141          $e->trigger();
 142          // The admin user should be added (realuserid).
 143          $this->setAdminUser();
 144          \core\session\manager::loginas($u2->id, \context_system::instance());
 145          $e = \logstore_standard\event\unittest_executed::create(['context' => $sysctx]);
 146          $e->trigger();
 147          // Set off an event in a different context. User 4 should not be returned below.
 148          $this->setUser($u4);
 149          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
 150          $e->trigger();
 151  
 152          provider::add_userids_for_context($userlist);
 153          $userids = $userlist->get_userids();
 154          $this->assertCount(4, $userids);
 155          $expectedresult = [$admin->id, $u1->id, $u2->id, $u3->id];
 156          $this->assertEmpty(array_diff($expectedresult, $userids));
 157      }
 158  
 159      public function test_delete_data_for_user() {
 160          global $DB;
 161          $u1 = $this->getDataGenerator()->create_user();
 162          $u2 = $this->getDataGenerator()->create_user();
 163          $c1 = $this->getDataGenerator()->create_course();
 164          $c2 = $this->getDataGenerator()->create_course();
 165          $sysctx = \context_system::instance();
 166          $c1ctx = \context_course::instance($c1->id);
 167          $c2ctx = \context_course::instance($c2->id);
 168  
 169          $this->enable_logging();
 170          $manager = get_log_manager(true);
 171  
 172          // User 1 is the author.
 173          $this->setUser($u1);
 174          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
 175          $e->trigger();
 176          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
 177          $e->trigger();
 178          $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx]);
 179          $e->trigger();
 180  
 181          // User 2 is the author.
 182          $this->setUser($u2);
 183          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
 184          $e->trigger();
 185          $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx]);
 186          $e->trigger();
 187  
 188          // Confirm data present.
 189          $this->assertTrue($DB->record_exists('logstore_standard_log', ['userid' => $u1->id, 'contextid' => $c1ctx->id]));
 190          $this->assertEquals(3, $DB->count_records('logstore_standard_log', ['userid' => $u1->id]));
 191          $this->assertEquals(2, $DB->count_records('logstore_standard_log', ['userid' => $u2->id]));
 192  
 193          // Delete all the things!
 194          provider::delete_data_for_user(new approved_contextlist($u1, 'logstore_standard', [$c1ctx->id]));
 195          $this->assertFalse($DB->record_exists('logstore_standard_log', ['userid' => $u1->id, 'contextid' => $c1ctx->id]));
 196          $this->assertEquals(1, $DB->count_records('logstore_standard_log', ['userid' => $u1->id]));
 197          $this->assertEquals(2, $DB->count_records('logstore_standard_log', ['userid' => $u2->id]));
 198      }
 199  
 200      public function test_delete_data_for_all_users_in_context() {
 201          global $DB;
 202          $u1 = $this->getDataGenerator()->create_user();
 203          $u2 = $this->getDataGenerator()->create_user();
 204          $c1 = $this->getDataGenerator()->create_course();
 205          $c2 = $this->getDataGenerator()->create_course();
 206          $sysctx = \context_system::instance();
 207          $c1ctx = \context_course::instance($c1->id);
 208          $c2ctx = \context_course::instance($c2->id);
 209  
 210          $this->enable_logging();
 211          $manager = get_log_manager(true);
 212  
 213          // User 1 is the author.
 214          $this->setUser($u1);
 215          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
 216          $e->trigger();
 217          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
 218          $e->trigger();
 219          $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx]);
 220          $e->trigger();
 221  
 222          // User 2 is the author.
 223          $this->setUser($u2);
 224          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
 225          $e->trigger();
 226          $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx]);
 227          $e->trigger();
 228  
 229          // Confirm data present.
 230          $this->assertTrue($DB->record_exists('logstore_standard_log', ['contextid' => $c1ctx->id]));
 231          $this->assertEquals(3, $DB->count_records('logstore_standard_log', ['userid' => $u1->id]));
 232          $this->assertEquals(2, $DB->count_records('logstore_standard_log', ['userid' => $u2->id]));
 233  
 234          // Delete all the things!
 235          provider::delete_data_for_all_users_in_context($c1ctx);
 236          $this->assertFalse($DB->record_exists('logstore_standard_log', ['contextid' => $c1ctx->id]));
 237          $this->assertEquals(1, $DB->count_records('logstore_standard_log', ['userid' => $u1->id]));
 238          $this->assertEquals(1, $DB->count_records('logstore_standard_log', ['userid' => $u2->id]));
 239      }
 240  
 241      public function test_delete_data_for_userlist() {
 242          global $DB;
 243  
 244          $u1 = $this->getDataGenerator()->create_user();
 245          $u2 = $this->getDataGenerator()->create_user();
 246          $u3 = $this->getDataGenerator()->create_user();
 247          $u4 = $this->getDataGenerator()->create_user();
 248  
 249          $course = $this->getDataGenerator()->create_course();
 250          $sysctx = \context_system::instance();
 251          $c1ctx = \context_course::instance($course->id);
 252  
 253          $this->enable_logging();
 254          $manager = get_log_manager(true);
 255  
 256          $this->setUser($u1);
 257          $e = \logstore_standard\event\unittest_executed::create(['context' => $sysctx]);
 258          $e->trigger();
 259          $this->setUser($u2);
 260          $e = \logstore_standard\event\unittest_executed::create(['context' => $sysctx]);
 261          $e->trigger();
 262          $this->setUser($u3);
 263          $e = \logstore_standard\event\unittest_executed::create(['context' => $sysctx]);
 264          $e->trigger();
 265          $this->setUser($u4);
 266          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx]);
 267          $e->trigger();
 268  
 269          // Check that four records were created.
 270          $this->assertEquals(4, $DB->count_records('logstore_standard_log'));
 271  
 272          $userlist = new \core_privacy\local\request\approved_userlist($sysctx, 'logstore_standard_log', [$u1->id, $u3->id]);
 273          provider::delete_data_for_userlist($userlist);
 274          // We should have a record for u2 and u4.
 275          $this->assertEquals(2, $DB->count_records('logstore_standard_log'));
 276  
 277          $records = $DB->get_records('logstore_standard_log', ['contextid' => $sysctx->id]);
 278          $this->assertCount(1, $records);
 279          $currentrecord = array_shift($records);
 280          $this->assertEquals($u2->id, $currentrecord->userid);
 281      }
 282  
 283      public function test_export_data_for_user() {
 284          $admin = \core_user::get_user(2);
 285          $u1 = $this->getDataGenerator()->create_user();
 286          $u2 = $this->getDataGenerator()->create_user();
 287          $u3 = $this->getDataGenerator()->create_user();
 288          $u4 = $this->getDataGenerator()->create_user();
 289          $c1 = $this->getDataGenerator()->create_course();
 290          $cm1 = $this->getDataGenerator()->create_module('url', ['course' => $c1]);
 291          $c2 = $this->getDataGenerator()->create_course();
 292          $cm2 = $this->getDataGenerator()->create_module('url', ['course' => $c2]);
 293          $sysctx = \context_system::instance();
 294          $c1ctx = \context_course::instance($c1->id);
 295          $c2ctx = \context_course::instance($c2->id);
 296          $cm1ctx = \context_module::instance($cm1->cmid);
 297          $cm2ctx = \context_module::instance($cm2->cmid);
 298  
 299          $path = [get_string('privacy:path:logs', 'tool_log'), get_string('pluginname', 'logstore_standard')];
 300          $this->enable_logging();
 301          $manager = get_log_manager(true);
 302  
 303          // User 1 is the author.
 304          $this->setUser($u1);
 305          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx, 'other' => ['i' => 0]]);
 306          $e->trigger();
 307  
 308          // User 2 is related.
 309          $this->setUser(0);
 310          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx, 'relateduserid' => $u2->id,
 311              'other' => ['i' => 1]]);
 312          $e->trigger();
 313  
 314          // Admin user masquerades u3, which is related to u4.
 315          $this->setAdminUser();
 316          \core\session\manager::loginas($u3->id, $sysctx);
 317          $e = \logstore_standard\event\unittest_executed::create(['context' => $c1ctx, 'relateduserid' => $u4->id,
 318              'other' => ['i' => 2]]);
 319          $e->trigger();
 320  
 321          // Confirm data present for u1.
 322          provider::export_user_data(new approved_contextlist($u1, 'logstore_standard', [$c2ctx->id, $c1ctx->id]));
 323          $data = writer::with_context($c2ctx)->get_data($path);
 324          $this->assertEmpty($data);
 325          $data = writer::with_context($c1ctx)->get_data($path);
 326          $this->assertCount(1, $data->logs);
 327          $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']);
 328          $this->assertSame(0, $data->logs[0]['other']['i']);
 329  
 330          // Confirm data present for u2.
 331          writer::reset();
 332          provider::export_user_data(new approved_contextlist($u2, 'logstore_standard', [$c2ctx->id, $c1ctx->id]));
 333          $data = writer::with_context($c2ctx)->get_data($path);
 334          $this->assertEmpty($data);
 335          $data = writer::with_context($c1ctx)->get_data($path);
 336          $this->assertCount(1, $data->logs);
 337          $this->assertEquals(transform::yesno(false), $data->logs[0]['author_of_the_action_was_you']);
 338          $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']);
 339          $this->assertSame(1, $data->logs[0]['other']['i']);
 340  
 341          // Confirm data present for u3.
 342          writer::reset();
 343          provider::export_user_data(new approved_contextlist($u3, 'logstore_standard', [$c2ctx->id, $c1ctx->id]));
 344          $data = writer::with_context($c2ctx)->get_data($path);
 345          $this->assertEmpty($data);
 346          $data = writer::with_context($c1ctx)->get_data($path);
 347          $this->assertCount(1, $data->logs);
 348          $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']);
 349          $this->assertEquals(transform::yesno(false), $data->logs[0]['related_user_was_you']);
 350          $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']);
 351          $this->assertEquals(transform::yesno(false), $data->logs[0]['masquerading_user_was_you']);
 352          $this->assertSame(2, $data->logs[0]['other']['i']);
 353  
 354          // Confirm data present for u4.
 355          writer::reset();
 356          provider::export_user_data(new approved_contextlist($u4, 'logstore_standard', [$c2ctx->id, $c1ctx->id]));
 357          $data = writer::with_context($c2ctx)->get_data($path);
 358          $this->assertEmpty($data);
 359          $data = writer::with_context($c1ctx)->get_data($path);
 360          $this->assertCount(1, $data->logs);
 361          $this->assertEquals(transform::yesno(false), $data->logs[0]['author_of_the_action_was_you']);
 362          $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']);
 363          $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']);
 364          $this->assertEquals(transform::yesno(false), $data->logs[0]['masquerading_user_was_you']);
 365          $this->assertSame(2, $data->logs[0]['other']['i']);
 366  
 367          // Add anonymous events.
 368          $this->setUser($u1);
 369          $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx, 'relateduserid' => $u2->id,
 370              'anonymous' => true]);
 371          $e->trigger();
 372          $this->setAdminUser();
 373          \core\session\manager::loginas($u3->id, $sysctx);
 374          $e = \logstore_standard\event\unittest_executed::create(['context' => $c2ctx, 'relateduserid' => $u4->id,
 375              'anonymous' => true]);
 376          $e->trigger();
 377  
 378          // Confirm data present for u1.
 379          provider::export_user_data(new approved_contextlist($u1, 'logstore_standard', [$c2ctx->id]));
 380          $data = writer::with_context($c2ctx)->get_data($path);
 381          $this->assertCount(1, $data->logs);
 382          $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']);
 383          $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']);
 384  
 385          // Confirm data present for u2.
 386          writer::reset();
 387          provider::export_user_data(new approved_contextlist($u2, 'logstore_standard', [$c2ctx->id]));
 388          $data = writer::with_context($c2ctx)->get_data($path);
 389          $this->assertCount(1, $data->logs);
 390          $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']);
 391          $this->assertArrayNotHasKey('author_of_the_action_was_you', $data->logs[0]);
 392          $this->assertArrayNotHasKey('authorid', $data->logs[0]);
 393          $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']);
 394  
 395          // Confirm data present for u3.
 396          writer::reset();
 397          provider::export_user_data(new approved_contextlist($u3, 'logstore_standard', [$c2ctx->id]));
 398          $data = writer::with_context($c2ctx)->get_data($path);
 399          $this->assertCount(1, $data->logs);
 400          $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']);
 401          $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_you']);
 402          $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']);
 403          $this->assertArrayNotHasKey('masquerading_user_was_you', $data->logs[0]);
 404          $this->assertArrayNotHasKey('masqueradinguserid', $data->logs[0]);
 405  
 406          // Confirm data present for u4.
 407          writer::reset();
 408          provider::export_user_data(new approved_contextlist($u4, 'logstore_standard', [$c2ctx->id]));
 409          $data = writer::with_context($c2ctx)->get_data($path);
 410          $this->assertCount(1, $data->logs);
 411          $this->assertEquals(transform::yesno(true), $data->logs[0]['action_was_done_anonymously']);
 412          $this->assertArrayNotHasKey('author_of_the_action_was_you', $data->logs[0]);
 413          $this->assertArrayNotHasKey('authorid', $data->logs[0]);
 414          $this->assertEquals(transform::yesno(true), $data->logs[0]['related_user_was_you']);
 415          $this->assertEquals(transform::yesno(true), $data->logs[0]['author_of_the_action_was_masqueraded']);
 416          $this->assertArrayNotHasKey('masquerading_user_was_you', $data->logs[0]);
 417          $this->assertArrayNotHasKey('masqueradinguserid', $data->logs[0]);
 418      }
 419  
 420      /**
 421       * Assert the content of a context list.
 422       *
 423       * @param contextlist $contextlist The collection.
 424       * @param array $expected List of expected contexts or IDs.
 425       * @return void
 426       */
 427      protected function assert_contextlist_equals($contextlist, array $expected) {
 428          $expectedids = array_map(function($context) {
 429              if (is_object($context)) {
 430                  return $context->id;
 431              }
 432              return $context;
 433          }, $expected);
 434          $contextids = array_map('intval', $contextlist->get_contextids());
 435          sort($contextids);
 436          sort($expectedids);
 437          $this->assertEquals($expectedids, $contextids);
 438      }
 439  
 440      /**
 441       * Enable logging.
 442       *
 443       * @return void
 444       */
 445      protected function enable_logging() {
 446          set_config('enabled_stores', 'logstore_standard', 'tool_log');
 447          set_config('buffersize', 0, 'logstore_standard');
 448          set_config('logguests', 1, 'logstore_standard');
 449      }
 450  
 451      /**
 452       * Get the contextlist for a user.
 453       *
 454       * @param object $user The user.
 455       * @return contextlist
 456       */
 457      protected function get_contextlist_for_user($user) {
 458          $contextlist = new contextlist();
 459          provider::add_contexts_for_userid($contextlist, $user->id);
 460          return $contextlist;
 461      }
 462  }