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  namespace qbank_comment\privacy;
  18  
  19  use comment;
  20  use context;
  21  use context_course;
  22  use core_privacy\local\metadata\collection;
  23  use qbank_comment\privacy\provider;
  24  use core_privacy\local\request\approved_userlist;
  25  use stdClass;
  26  
  27  /**
  28   * Privacy api tests.
  29   *
  30   * @package    qbank_comment
  31   * @copyright  2021 Catalyst IT Australia Pty Ltd
  32   * @author     Safat Shahin <safatshahin@catalyst-au.net>
  33   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  class provider_test extends \core_privacy\tests\provider_testcase {
  36  
  37      /** @var stdClass A teacher who is only enrolled in course1. */
  38      protected $teacher1;
  39  
  40      /** @var stdClass A teacher who is only enrolled in course2. */
  41      protected $teacher2;
  42  
  43      /** @var stdClass A teacher who is enrolled in both course1 and course2. */
  44      protected $teacher3;
  45  
  46      /** @var stdClass A test course. */
  47      protected $course1;
  48  
  49      /** @var stdClass A test course. */
  50      protected $course2;
  51  
  52      /**
  53       * Set up function for tests in this class.
  54       */
  55      protected function setUp(): void {
  56          global $DB;
  57  
  58          $this->resetAfterTest();
  59          $this->setAdminUser();
  60  
  61          // Create courses.
  62          $generator = $this->getDataGenerator();
  63          $this->course1 = $generator->create_course();
  64          $this->course2 = $generator->create_course();
  65  
  66          // Create and enrol teachers.
  67          $this->teacher1 = $generator->create_user();
  68          $this->teacher2 = $generator->create_user();
  69          $this->teacher3 = $generator->create_user();
  70  
  71          $studentrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
  72          $generator->enrol_user($this->teacher1->id,  $this->course1->id, $studentrole->id);
  73          $generator->enrol_user($this->teacher2->id,  $this->course2->id, $studentrole->id);
  74          $generator->enrol_user($this->teacher3->id,  $this->course1->id, $studentrole->id);
  75          $generator->enrol_user($this->teacher3->id,  $this->course2->id, $studentrole->id);
  76      }
  77  
  78      /**
  79       * Posts a comment on a given context.
  80       *
  81       * @param string $text The comment's text.
  82       * @param context $context The context on which we want to put the comment.
  83       */
  84      protected function add_comment($text, context $context) {
  85          $args = new stdClass;
  86          $args->context = $context;
  87          $args->area = 'question';
  88          $args->itemid = 0;
  89          $args->component = 'qbank_comment';
  90          $args->linktext = get_string('commentheader', 'qbank_comment');
  91          $args->notoggle = true;
  92          $args->autostart = true;
  93          $args->displaycancel = false;
  94          $comment = new comment($args);
  95  
  96          $comment->add($text);
  97      }
  98  
  99      /**
 100       * Test for provider::get_metadata().
 101       */
 102      public function test_get_metadata() {
 103          $collection = new collection('qbank_comment');
 104          $newcollection = provider::get_metadata($collection);
 105          $itemcollection = $newcollection->get_collection();
 106          $this->assertCount(1, $itemcollection);
 107  
 108          $link = reset($itemcollection);
 109  
 110          $this->assertEquals('core_comment', $link->get_name());
 111          $this->assertEmpty($link->get_privacy_fields());
 112          $this->assertEquals('privacy:metadata:core_comment', $link->get_summary());
 113      }
 114  
 115      /**
 116       * Test for provider::get_contexts_for_userid() when user had not posted any comments..
 117       */
 118      public function test_get_contexts_for_userid_no_comment() {
 119          $this->setUser($this->teacher1);
 120          $coursecontext1 = context_course::instance($this->course1->id);
 121          $this->add_comment('New comment', $coursecontext1);
 122  
 123          $this->setUser($this->teacher2);
 124          $contextlist = provider::get_contexts_for_userid($this->teacher2->id);
 125          $this->assertCount(0, $contextlist);
 126      }
 127  
 128      /**
 129       * Test for provider::get_contexts_for_userid().
 130       */
 131      public function test_get_contexts_for_userid() {
 132          $coursecontext1 = context_course::instance($this->course1->id);
 133          $coursecontext2 = context_course::instance($this->course2->id);
 134  
 135          $this->setUser($this->teacher3);
 136          $this->add_comment('New comment', $coursecontext1);
 137          $this->add_comment('New comment', $coursecontext1);
 138          $this->add_comment('New comment', $coursecontext2);
 139  
 140          $contextlist = provider::get_contexts_for_userid($this->teacher3->id);
 141          $this->assertCount(2, $contextlist);
 142  
 143          $contextids = $contextlist->get_contextids();
 144          $this->assertEqualsCanonicalizing([$coursecontext1->id, $coursecontext2->id], $contextids);
 145      }
 146  
 147      /**
 148       * Test for provider::export_user_data() when the user has not posted any comments.
 149       */
 150      public function test_export_for_context_no_comment() {
 151          $coursecontext1 = context_course::instance($this->course1->id);
 152          $coursecontext2 = context_course::instance($this->course2->id);
 153  
 154          $this->setUser($this->teacher1);
 155          $this->add_comment('New comment', $coursecontext1);
 156  
 157          $this->setUser($this->teacher2);
 158  
 159          $this->setUser($this->teacher2);
 160          $this->export_context_data_for_user($this->teacher1->id, $coursecontext2, 'qbank_comment');
 161          $writer = \core_privacy\local\request\writer::with_context($coursecontext2);
 162          $this->assertFalse($writer->has_any_data());
 163      }
 164  
 165      /**
 166       * Test for provider::export_user_data().
 167       */
 168      public function test_export_for_context() {
 169          $coursecontext1 = context_course::instance($this->course1->id);
 170          $coursecontext2 = context_course::instance($this->course2->id);
 171  
 172          $this->setUser($this->teacher3);
 173          $this->add_comment('New comment', $coursecontext1);
 174          $this->add_comment('New comment', $coursecontext1);
 175          $this->add_comment('New comment', $coursecontext2);
 176  
 177          // Export all of the data for the context.
 178          $this->export_context_data_for_user($this->teacher3->id, $coursecontext1, 'qbank_comment');
 179          $writer = \core_privacy\local\request\writer::with_context($coursecontext1);
 180          $this->assertTrue($writer->has_any_data());
 181      }
 182  
 183      /**
 184       * Test for provider::delete_data_for_all_users_in_context().
 185       */
 186      public function test_delete_data_for_all_users_in_context() {
 187          global $DB;
 188  
 189          $coursecontext1 = context_course::instance($this->course1->id);
 190          $coursecontext2 = context_course::instance($this->course2->id);
 191  
 192          $this->setUser($this->teacher1);
 193          $this->add_comment('New comment', $coursecontext1);
 194  
 195          $this->setUser($this->teacher2);
 196          $this->add_comment('New comment', $coursecontext2);
 197  
 198          $this->setUser($this->teacher3);
 199          $this->add_comment('New comment', $coursecontext1);
 200          $this->add_comment('New comment', $coursecontext1);
 201          $this->add_comment('New comment', $coursecontext2);
 202  
 203          // Before deletion, we should have 3 comments in $coursecontext1 and 2 comments in $coursecontext2.
 204          $this->assertEquals(
 205                  3,
 206                  $DB->count_records('comments', ['component' => 'qbank_comment', 'contextid' => $coursecontext1->id])
 207          );
 208          $this->assertEquals(
 209                  2,
 210                  $DB->count_records('comments', ['component' => 'qbank_comment', 'contextid' => $coursecontext2->id])
 211          );
 212  
 213          // Delete data based on context.
 214          provider::delete_data_for_all_users_in_context($coursecontext1);
 215  
 216          // After deletion, the comments for $coursecontext1 should have been deleted.
 217          $this->assertEquals(
 218                  0,
 219                  $DB->count_records('comments', ['component' => 'qbank_comment', 'contextid' => $coursecontext1->id])
 220          );
 221          $this->assertEquals(
 222                  2,
 223                  $DB->count_records('comments', ['component' => 'qbank_comment', 'contextid' => $coursecontext2->id])
 224          );
 225      }
 226  
 227      /**
 228       * Test for provider::delete_data_for_user().
 229       */
 230      public function test_delete_data_for_user() {
 231          global $DB;
 232  
 233          $coursecontext1 = context_course::instance($this->course1->id);
 234          $coursecontext2 = context_course::instance($this->course2->id);
 235  
 236          $this->setUser($this->teacher1);
 237          $this->add_comment('New comment', $coursecontext1);
 238  
 239          $this->setUser($this->teacher2);
 240          $this->add_comment('New comment', $coursecontext2);
 241  
 242          $this->setUser($this->teacher3);
 243          $this->add_comment('New comment', $coursecontext1);
 244          $this->add_comment('New comment', $coursecontext1);
 245          $this->add_comment('New comment', $coursecontext2);
 246  
 247          // Before deletion, we should have 3 comments in $coursecontext1 and 2 comments in $coursecontext2,
 248          // and 3 comments by student12 in $coursecontext1 and $coursecontext2 combined.
 249          $this->assertEquals(
 250                  3,
 251                  $DB->count_records('comments', ['component' => 'qbank_comment', 'contextid' => $coursecontext1->id])
 252          );
 253          $this->assertEquals(
 254                  2,
 255                  $DB->count_records('comments', ['component' => 'qbank_comment', 'contextid' => $coursecontext2->id])
 256          );
 257          $this->assertEquals(
 258                  3,
 259                  $DB->count_records('comments', ['component' => 'qbank_comment', 'userid' => $this->teacher3->id])
 260          );
 261  
 262          $contextlist = new \core_privacy\local\request\approved_contextlist($this->teacher3, 'qbank_comment',
 263                  [$coursecontext1->id, $coursecontext2->id]);
 264          provider::delete_data_for_user($contextlist);
 265  
 266          // After deletion, the comments for the student12 should have been deleted.
 267          $this->assertEquals(
 268                  1,
 269                  $DB->count_records('comments', ['component' => 'qbank_comment', 'contextid' => $coursecontext1->id])
 270          );
 271          $this->assertEquals(
 272                  1,
 273                  $DB->count_records('comments', ['component' => 'qbank_comment', 'contextid' => $coursecontext2->id])
 274          );
 275          $this->assertEquals(
 276                  0,
 277                  $DB->count_records('comments', ['component' => 'qbank_comment', 'userid' => $this->teacher3->id])
 278          );
 279      }
 280  
 281      /**
 282       * Test that only users within a course context are fetched.
 283       */
 284      public function test_get_users_in_context() {
 285          $component = 'qbank_comment';
 286  
 287          $coursecontext1 = context_course::instance($this->course1->id);
 288          $coursecontext2 = context_course::instance($this->course2->id);
 289  
 290          $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component);
 291          provider::get_users_in_context($userlist1);
 292          $this->assertCount(0, $userlist1);
 293  
 294          $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component);
 295          provider::get_users_in_context($userlist2);
 296          $this->assertCount(0, $userlist2);
 297  
 298          $this->setUser($this->teacher3);
 299          $this->add_comment('New comment', $coursecontext1);
 300          $this->add_comment('New comment', $coursecontext2);
 301          $this->setUser($this->teacher1);
 302          $this->add_comment('New comment', $coursecontext1);
 303  
 304          // The list of users should contain teacher3 and user1.
 305          provider::get_users_in_context($userlist1);
 306          $this->assertCount(2, $userlist1);
 307          $this->assertTrue(in_array($this->teacher1->id, $userlist1->get_userids()));
 308          $this->assertTrue(in_array($this->teacher3->id, $userlist1->get_userids()));
 309  
 310          // The list of users should contain teacher3.
 311          provider::get_users_in_context($userlist2);
 312          $this->assertCount(1, $userlist2);
 313          $expected = [$this->teacher3->id];
 314          $actual = $userlist2->get_userids();
 315          $this->assertEquals($expected, $actual);
 316      }
 317  
 318      /**
 319       * Test that data for users in approved userlist is deleted.
 320       */
 321      public function test_delete_data_for_users() {
 322          $component = 'qbank_comment';
 323  
 324          $coursecontext1 = context_course::instance($this->course1->id);
 325          $coursecontext2 = context_course::instance($this->course2->id);
 326  
 327          $this->setUser($this->teacher3);
 328          $this->add_comment('New comment', $coursecontext1);
 329          $this->add_comment('New comment', $coursecontext2);
 330          $this->setUser($this->teacher1);
 331          $this->add_comment('New comment', $coursecontext1);
 332  
 333          $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component);
 334          provider::get_users_in_context($userlist1);
 335          $this->assertCount(2, $userlist1);
 336  
 337          $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component);
 338          provider::get_users_in_context($userlist2);
 339          $this->assertCount(1, $userlist2);
 340  
 341          // Convert $userlist1 into an approved_contextlist.
 342          $approvedlist1 = new approved_userlist($coursecontext1, $component, $userlist1->get_userids());
 343          // Delete using delete_data_for_user.
 344          provider::delete_data_for_users($approvedlist1);
 345  
 346          // Re-fetch users in coursecontext1.
 347          $userlist1 = new \core_privacy\local\request\userlist($coursecontext1, $component);
 348          provider::get_users_in_context($userlist1);
 349          // The user data in coursecontext1 should be deleted.
 350          $this->assertCount(0, $userlist1);
 351  
 352          // Re-fetch users in coursecontext2.
 353          $userlist2 = new \core_privacy\local\request\userlist($coursecontext2, $component);
 354          provider::get_users_in_context($userlist2);
 355          // The user data in coursecontext2 should be still present.
 356          $this->assertCount(1, $userlist2);
 357      }
 358  }