Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310]

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