Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.
   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   * Base class for unit tests for core_contentbank.
  19   *
  20   * @package    core_contentbank
  21   * @category   test
  22   * @copyright  2020 Carlos Escobedo <carlos@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  namespace core_contentbank\privacy;
  27  
  28  use stdClass;
  29  use context_system;
  30  use context_coursecat;
  31  use context_course;
  32  use context_user;
  33  use core_contentbank\privacy\provider;
  34  use core_privacy\local\request\approved_contextlist;
  35  use core_privacy\local\request\writer;
  36  use core_privacy\tests\provider_testcase;
  37  use core_privacy\local\request\userlist;
  38  use core_privacy\local\request\approved_userlist;
  39  
  40  /**
  41   * Unit tests for contentbank\classes\privacy\provider.php
  42   *
  43   * @copyright  2020 Carlos Escobedo <carlos@moodle.com>
  44   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  45   */
  46  class provider_test extends provider_testcase {
  47  
  48      /**
  49       * Setup to ensure that fixtures are loaded.
  50       */
  51      public static function setupBeforeClass(): void {
  52          global $CFG;
  53          require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
  54      }
  55  
  56      /**
  57       * Test for provider::get_contexts_for_userid().
  58       */
  59      public function test_get_contexts_for_userid() {
  60  
  61          $this->resetAfterTest();
  62          // Setup scenario.
  63          $scenario = $this->setup_scenario();
  64  
  65          // Testing againts Manager who has content in the three contexts.
  66          $contextlist = provider::get_contexts_for_userid($scenario->manager->id);
  67          // There are three contexts in the list.
  68          $contextlistids = $contextlist->get_contextids();
  69          $this->assertCount(3, $contextlistids);
  70          // Check the list against the expected list of contexts.
  71          $this->assertContainsEquals($scenario->systemcontext->id, $contextlistids);
  72          $this->assertContainsEquals($scenario->coursecategorycontext->id,
  73              $contextlistids);
  74          $this->assertContainsEquals($scenario->coursecontext->id, $contextlistids);
  75  
  76          // Testing againts Teacher who has content in the one context.
  77          $contextlist = provider::get_contexts_for_userid($scenario->teacher->id);
  78          // There are only one context in the list.
  79          $contextlistids = $contextlist->get_contextids();
  80          $this->assertCount(1, $contextlistids);
  81          // Check the againts Course Context.
  82          $this->assertContainsEquals($scenario->coursecontext->id, $contextlistids);
  83          // And there is not a System and Course Category Context.
  84          $this->assertNotContainsEquals($scenario->systemcontext->id, $contextlistids);
  85          $this->assertNotContainsEquals($scenario->coursecategorycontext->id, $contextlistids);
  86      }
  87  
  88      /**
  89       * Test for provider::get_users_in_context().
  90       */
  91      public function test_get_users_in_context() {
  92  
  93          $this->resetAfterTest();
  94          // Setup scenario.
  95          $scenario = $this->setup_scenario();
  96  
  97          // Get the userlist to Context System, only Manager will be there.
  98          $userlist = new userlist($scenario->systemcontext, 'core_contentbank');
  99          provider::get_users_in_context($userlist);
 100          $this->assertEquals([$scenario->manager->id], $userlist->get_userids());
 101          // Teacher will not be there.
 102          $this->assertNotEquals([$scenario->teacher->id], $userlist->get_userids());
 103  
 104          // Get the userlist to Context Course, Manager and Teacher will be there.
 105          $userlist = new userlist($scenario->coursecontext, 'core_contentbank');
 106          provider::get_users_in_context($userlist);
 107  
 108          $expected = [$scenario->manager->id, $scenario->teacher->id];
 109          sort($expected);
 110          $actual = $userlist->get_userids();
 111          sort($actual);
 112          $this->assertEquals($expected, $actual);
 113      }
 114  
 115      /**
 116       * Test for provider::test_export_user_data().
 117       */
 118      public function test_export_user_data() {
 119  
 120          $this->resetAfterTest();
 121          // Setup scenario.
 122          $scenario = $this->setup_scenario();
 123  
 124          $subcontexts = [
 125              get_string('name', 'core_contentbank')
 126          ];
 127          // Get the data for the System Context.
 128          $writer = writer::with_context($scenario->systemcontext);
 129          $this->assertFalse($writer->has_any_data());
 130          // Export data for Manager.
 131          $this->export_context_data_for_user($scenario->manager->id,
 132              $scenario->systemcontext, 'core_contentbank');
 133          $data = $writer->get_data($subcontexts);
 134          $this->assertCount(3, (array) $data);
 135          $this->assertCount(3, $writer->get_files($subcontexts));
 136  
 137          // Get the data for the Course Categoy Context.
 138          $writer = writer::with_context($scenario->coursecategorycontext);
 139          // Export data for Manager.
 140          $this->export_context_data_for_user($scenario->manager->id,
 141              $scenario->coursecategorycontext, 'core_contentbank');
 142          $data = $writer->get_data($subcontexts);
 143          $this->assertCount(2, (array) $data);
 144          $this->assertCount(2, $writer->get_files($subcontexts));
 145  
 146          // Get the data for the Course Context.
 147          $writer = writer::with_context($scenario->coursecontext);
 148          // Export data for Manager.
 149          $this->export_context_data_for_user($scenario->manager->id,
 150              $scenario->coursecontext, 'core_contentbank');
 151          $data = $writer->get_data($subcontexts);
 152          $this->assertCount(2, (array) $data);
 153          $this->assertCount(2, $writer->get_files($subcontexts));
 154  
 155          // Export data for Teacher.
 156          $writer = writer::reset();
 157          $writer = writer::with_context($scenario->coursecontext);
 158          $this->export_context_data_for_user($scenario->teacher->id,
 159              $scenario->coursecontext, 'core_contentbank');
 160          $data = $writer->get_data($subcontexts);
 161          $this->assertCount(3, (array) $data);
 162          $this->assertCount(3, $writer->get_files($subcontexts));
 163      }
 164  
 165      /**
 166       * Test for provider::delete_data_for_all_users_in_context().
 167       */
 168      public function test_delete_data_for_all_users_in_context() {
 169          global $DB;
 170  
 171          $this->resetAfterTest();
 172          // Setup scenario.
 173          $scenario = $this->setup_scenario();
 174  
 175          // Before delete data, we have 4 contents.
 176          // - 3 in a system context.
 177          // - 2 in a course category context.
 178          // - 5 in a course context (2 by manager and 3 by teacher).
 179  
 180          // Delete data based on system context.
 181          provider::delete_data_for_all_users_in_context($scenario->systemcontext);
 182          $count = $DB->count_records('contentbank_content');
 183          // 3 content should be deleted.
 184          // 7 contents should be remain.
 185          $this->assertEquals(7, $count);
 186  
 187          // Delete data based on course category context.
 188          provider::delete_data_for_all_users_in_context($scenario->coursecategorycontext);
 189          $count = $DB->count_records('contentbank_content');
 190          // 2 contents should be deleted.
 191          // 5 content should be remain.
 192          $this->assertEquals(5, $count);
 193  
 194          // Delete data based on course context.
 195          provider::delete_data_for_all_users_in_context($scenario->coursecontext);
 196           $count = $DB->count_records('contentbank_content');
 197          // 5 content should be deleted.
 198          // 0 content should be remain.
 199          $this->assertEquals(0, $count);
 200      }
 201  
 202      /**
 203       * Test for provider::test_delete_data_for_users().
 204       */
 205      public function test_delete_data_for_users() {
 206          global $DB;
 207  
 208          $this->resetAfterTest();
 209          // Setup scenario.
 210          $scenario = $this->setup_scenario();
 211  
 212          // Before delete data, we have 4 contents.
 213          // - 3 in a system context.
 214          // - 2 in a course category context.
 215          // - 5 in a course context (2 by manager and 3 by teacher).
 216  
 217          // A list of users who has created content in Course Category Context.
 218          $userlist1 = new userlist($scenario->coursecategorycontext,
 219              'core_contentbank');
 220          provider::get_users_in_context($userlist1);
 221          $this->assertCount(1, $userlist1);
 222          // Only Manager should be.
 223          $this->assertEquals([$scenario->manager->id], $userlist1->get_userids());
 224  
 225          // A list of users who has created content in Course Context.
 226          $userlist2 = new userlist($scenario->coursecontext, 'core_contentbank');
 227          provider::get_users_in_context($userlist2);
 228          $this->assertCount(2, $userlist2);
 229  
 230          // Manager and Teacher should be.
 231          $expected = [$scenario->manager->id, $scenario->teacher->id];
 232          sort($expected);
 233          $actual = $userlist2->get_userids();
 234          sort($actual);
 235          $this->assertEquals($expected, $actual);
 236  
 237          // Convert $userlist1 into an approved_contextlist.
 238          $approvedlist1 = new approved_userlist($scenario->coursecategorycontext, 'core_contentbank', $userlist1->get_userids());
 239          // Delete data for users in course category context.
 240          provider::delete_data_for_users($approvedlist1);
 241  
 242          // Re-fetch users in course category context.
 243          $userlist1 = new userlist($scenario->coursecategorycontext,
 244              'core_contentbank');
 245          provider::get_users_in_context($userlist1);
 246          // The user data in course category context should be deleted.
 247          $this->assertCount(0, $userlist1);
 248          // Re-fetch users in course category context.
 249          $userlist2 = new userlist($scenario->coursecontext, 'core_contentbank');
 250          provider::get_users_in_context($userlist2);
 251          // The user data in course context should be still present.
 252          $this->assertCount(2, $userlist2);
 253  
 254          // Convert $userlist2 into an approved_contextlist.
 255          $approvedlist2 = new approved_userlist($scenario->coursecontext,
 256              'core_contentbank', $userlist2->get_userids());
 257          // Delete data for users in course context.
 258          provider::delete_data_for_users($approvedlist2);
 259          $userlist2 = new userlist($scenario->coursecontext, 'core_contentbank');
 260          provider::get_users_in_context($userlist2);
 261          // The user data in course context should be deleted.
 262          $this->assertCount(0, $userlist2);
 263      }
 264  
 265      /**
 266       * Test for provider::delete_data_for_user().
 267       */
 268      public function test_delete_data_for_user() {
 269           global $DB;
 270  
 271          $this->resetAfterTest();
 272          // Setup scenario.
 273          $scenario = $this->setup_scenario();
 274  
 275          // Before delete data, we have 4 contents.
 276          // - 3 in a system context.
 277          // - 2 in a course category context.
 278          // - 5 in a course context (2 by manager and 3 by teacher).
 279  
 280          // Get all the context for Manager.
 281          $contextlist = provider::get_contexts_for_userid($scenario->manager->id);
 282          $approvedcontextlist = new approved_contextlist($scenario->manager,
 283              'core_contentbank', $contextlist->get_contextids());
 284          // Delete all the data created by the Manager in all the contexts.
 285          provider::delete_data_for_user($approvedcontextlist);
 286  
 287          // After deletion, only 3 content for teacher should be present.
 288          $count = $DB->count_records('contentbank_content');
 289          $this->assertEquals(3, $count);
 290  
 291          // Confirm that the remaining content was created by the teacher.
 292          $count = $DB->count_records('contentbank_content',
 293              ['usercreated' => $scenario->teacher->id]);
 294          $this->assertEquals(3, $count);
 295  
 296          // Get all the context for Teacher.
 297          $contextlist = provider::get_contexts_for_userid($scenario->teacher->id);
 298          $approvedcontextlist = new approved_contextlist($scenario->teacher,
 299              'core_contentbank', $contextlist->get_contextids());
 300          // Delete all the data created by the Teacher in all the contexts.
 301          provider::delete_data_for_user($approvedcontextlist);
 302  
 303          // After deletion, no content should be present.
 304          $count = $DB->count_records('contentbank_content');
 305          $this->assertEquals(0, $count);
 306      }
 307  
 308      /**
 309       * Create a complex scenario to use into the tests.
 310       *
 311       * @return stdClass $scenario
 312       */
 313      protected function setup_scenario() {
 314          global $DB;
 315  
 316          $systemcontext = context_system::instance();
 317          $manager = $this->getDataGenerator()->create_user();
 318          $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
 319          $this->getDataGenerator()->role_assign($managerroleid, $manager->id);
 320  
 321          $coursecategory = $this->getDataGenerator()->create_category();
 322          $coursecategorycontext = context_coursecat::instance($coursecategory->id);
 323  
 324          $course = $this->getDataGenerator()->create_course();
 325          $coursecontext = context_course::instance($course->id);
 326          $teacher = $this->getDataGenerator()->create_and_enrol($course,
 327              'editingteacher');
 328  
 329          // Add some content to the content bank.
 330          $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
 331          // Add contents by Manager in Context System.
 332          $records = $generator->generate_contentbank_data('contenttype_testable',
 333              1, $manager->id, $systemcontext, false, 'systemtestfile1.h5p');
 334          $records = $generator->generate_contentbank_data('contenttype_testable',
 335              1, $manager->id, $systemcontext, false, 'systemtestfile2.h5p');
 336          $records = $generator->generate_contentbank_data('contenttype_testable',
 337              1, $manager->id, $systemcontext, false, 'systemtestfile3.h5p');
 338          // Add contents by Manager in Context Course Category.
 339          $records = $generator->generate_contentbank_data('contenttype_testable',
 340              1, $manager->id, $coursecategorycontext, false, 'coursecattestfile1.h5p');
 341          $records = $generator->generate_contentbank_data('contenttype_testable',
 342              1, $manager->id, $coursecategorycontext, false, 'coursecattestfile2.h5p');
 343          // Add contents by Manager in Context Course.
 344          $records = $generator->generate_contentbank_data('contenttype_testable',
 345              1, $manager->id, $coursecontext, false, 'coursetestfile1.h5p');
 346          $records = $generator->generate_contentbank_data('contenttype_testable',
 347              1, $manager->id, $coursecontext, false, 'coursetestfile2.h5p');
 348          // Add contents by Teacher.
 349          $records = $generator->generate_contentbank_data('contenttype_testable',
 350              1, $teacher->id, $coursecontext, false, 'courseteacherfile1.h5p');
 351          $records = $generator->generate_contentbank_data('contenttype_testable',
 352              1, $teacher->id, $coursecontext, false, 'courseteacherfile2.h5p');
 353          $records = $generator->generate_contentbank_data('contenttype_testable',
 354              1, $teacher->id, $coursecontext, false, 'courseteacherfile3.h5p');
 355  
 356          $scenario = new stdClass();
 357          $scenario->systemcontext = $systemcontext;
 358          $scenario->coursecategorycontext = $coursecategorycontext;
 359          $scenario->coursecontext = $coursecontext;
 360          $scenario->manager = $manager;
 361          $scenario->teacher = $teacher;
 362  
 363          return $scenario;
 364      }
 365  
 366      /**
 367       * Ensure that export_user_preferences returns no data if the user has not visited any content bank.
 368       */
 369      public function test_export_user_preferences_no_pref() {
 370          global $DB;
 371  
 372          $this->resetAfterTest();
 373          $user = $this->getDataGenerator()->create_user();
 374          $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
 375          $this->getDataGenerator()->role_assign($managerroleid, $user->id);
 376  
 377          provider::export_user_preferences($user->id);
 378          $writer = writer::with_context(context_system::instance());
 379          $this->assertFalse($writer->has_any_data());
 380      }
 381  
 382      /**
 383       * Test for provider::test_export_user_preferences().
 384       */
 385      public function test_export_user_preferences() {
 386          global $DB;
 387  
 388          // Test setup.
 389          $this->resetAfterTest(true);
 390          $user = $this->getDataGenerator()->create_user();
 391          $this->setUser($user);
 392  
 393          set_user_preference('core_contentbank_view_list', 1);
 394          // Test the user preferences export contains 1 user preference record for the User.
 395          provider::export_user_preferences($user->id);
 396          $contextuser = context_user::instance($user->id);
 397          $writer = writer::with_context($contextuser);
 398          $this->assertTrue($writer->has_any_data());
 399  
 400          $prefs = $writer->get_user_preferences('core_contentbank');
 401          $this->assertCount(1, (array) $prefs);
 402          $this->assertEquals(1, $prefs->core_contentbank_view_list->value);
 403          $this->assertEquals(
 404                  get_string('privacy:request:preference:set', 'core_contentbank', (object) [
 405                          'name' => 'core_contentbank_view_list',
 406                          'value' => $prefs->core_contentbank_view_list->value,
 407                  ]),
 408                  $prefs->core_contentbank_view_list->description
 409          );
 410      }
 411  }