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   * Privacy provider tests.
  19   *
  20   * @package     mod_glossary
  21   * @copyright   2018 Simey Lameze <simey@moodle.com>
  22   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  use core_privacy\local\metadata\collection;
  26  use core_privacy\local\request\deletion_criteria;
  27  use mod_glossary\privacy\provider;
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  global $CFG;
  32  require_once($CFG->dirroot . '/comment/lib.php');
  33  require_once($CFG->dirroot . '/rating/lib.php');
  34  
  35  /**
  36   * Privacy provider tests class.
  37   *
  38   * @package    mod_glossary
  39   * @copyright 2018 Simey Lameze <simey@moodle.com>
  40   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41   */
  42  class mod_glossary_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
  43      /** @var stdClass The student object. */
  44      protected $student;
  45  
  46      /** @var stdClass The teacher object. */
  47      protected $teacher;
  48  
  49      /** @var stdClass The glossary object. */
  50      protected $glossary;
  51  
  52      /** @var stdClass The course object. */
  53      protected $course;
  54  
  55      /** @var stdClass The plugin generator object. */
  56      protected $plugingenerator;
  57  
  58      /**
  59       * {@inheritdoc}
  60       */
  61      protected function setUp() {
  62          $this->resetAfterTest();
  63  
  64          global $DB;
  65          $generator = $this->getDataGenerator();
  66          $course = $generator->create_course();
  67          $this->course = $course;
  68  
  69          $this->plugingenerator = $generator->get_plugin_generator('mod_glossary');
  70  
  71          // The glossary activity the user will answer.
  72          $glossary = $this->plugingenerator->create_instance(['course' => $course->id]);
  73          $this->glossary = $glossary;
  74  
  75          $cm = get_coursemodule_from_instance('glossary', $glossary->id);
  76          $context = context_module::instance($cm->id);
  77  
  78          // Create a student which will add an entry to a glossary.
  79          $student = $generator->create_user();
  80          $generator->enrol_user($student->id,  $course->id, 'student');
  81          $this->student = $student;
  82  
  83          $teacher = $generator->create_user();
  84          $generator->enrol_user($teacher->id,  $course->id, 'editingteacher');
  85          $this->teacher = $teacher;
  86  
  87          $this->setUser($student->id);
  88          $ge1 = $this->plugingenerator->create_content($glossary, ['concept' => 'first', 'approved' => 1], ['one']);
  89  
  90          // Student create a comment on a glossary entry.
  91          $this->setUser($student);
  92          $comment = $this->get_comment_object($context, $ge1->id);
  93          $comment->add('Hello, it\'s me!');
  94  
  95          // Attach tags.
  96          core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge1->id, $context, ['Beer', 'Golf']);
  97      }
  98  
  99      /**
 100       * Test for provider::get_metadata().
 101       */
 102      public function test_get_metadata() {
 103          $collection = new collection('mod_glossary');
 104          $newcollection = provider::get_metadata($collection);
 105          $itemcollection = $newcollection->get_collection();
 106          $this->assertCount(5, $itemcollection);
 107  
 108          $table = reset($itemcollection);
 109          $this->assertEquals('glossary_entries', $table->get_name());
 110  
 111          $privacyfields = $table->get_privacy_fields();
 112          $this->assertArrayHasKey('glossaryid', $privacyfields);
 113          $this->assertArrayHasKey('concept', $privacyfields);
 114          $this->assertArrayHasKey('definition', $privacyfields);
 115          $this->assertArrayHasKey('attachment', $privacyfields);
 116          $this->assertArrayHasKey('userid', $privacyfields);
 117          $this->assertArrayHasKey('timemodified', $privacyfields);
 118  
 119          $this->assertEquals('privacy:metadata:glossary_entries', $table->get_summary());
 120      }
 121  
 122      /**
 123       * Test for provider::get_contexts_for_userid().
 124       */
 125      public function test_get_contexts_for_userid() {
 126          $cm = get_coursemodule_from_instance('glossary', $this->glossary->id);
 127  
 128          $contextlist = provider::get_contexts_for_userid($this->student->id);
 129          $this->assertCount(1, $contextlist);
 130          $contextforuser = $contextlist->current();
 131          $cmcontext = context_module::instance($cm->id);
 132          $this->assertEquals($cmcontext->id, $contextforuser->id);
 133      }
 134  
 135      /**
 136       * Test for provider::get_users_in_context().
 137       */
 138      public function test_get_users_in_context() {
 139          $component = 'mod_glossary';
 140          $cm = get_coursemodule_from_instance('glossary', $this->glossary->id);
 141          $cmcontext = context_module::instance($cm->id);
 142  
 143          $userlist = new \core_privacy\local\request\userlist($cmcontext, $component);
 144          provider::get_users_in_context($userlist);
 145  
 146          $this->assertCount(1, $userlist);
 147  
 148          $expected = [$this->student->id];
 149          $actual = $userlist->get_userids();
 150          sort($expected);
 151          sort($actual);
 152  
 153          $this->assertEquals($expected, $actual);
 154      }
 155  
 156      /**
 157       * Test for provider::export_user_data().
 158       */
 159      public function test_export_for_context() {
 160          $cm = get_coursemodule_from_instance('glossary', $this->glossary->id);
 161          $cmcontext = context_module::instance($cm->id);
 162  
 163          // Export all of the data for the context.
 164          $writer = \core_privacy\local\request\writer::with_context($cmcontext);
 165          $contextlist = new \core_privacy\local\request\approved_contextlist($this->student, 'mod_glossary' , [$cmcontext->id]);
 166  
 167          \mod_glossary\privacy\provider::export_user_data($contextlist);
 168          $this->assertTrue($writer->has_any_data());
 169          $data = $writer->get_data([]);
 170  
 171          $this->assertEquals('Glossary 1', $data->name);
 172          $this->assertEquals('first', $data->entries[0]['concept']);
 173      }
 174  
 175      /**
 176       * Test for provider::delete_data_for_all_users_in_context().
 177       */
 178      public function test_delete_data_for_all_users_in_context() {
 179          global $DB;
 180  
 181          $generator = $this->getDataGenerator();
 182          $cm = get_coursemodule_from_instance('glossary', $this->glossary->id);
 183          $context = context_module::instance($cm->id);
 184          // Create another student who will add an entry the glossary activity.
 185          $student2 = $generator->create_user();
 186          $generator->enrol_user($student2->id, $this->course->id, 'student');
 187  
 188          $this->setUser($student2);
 189          $ge3 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'first', 'approved' => 1], ['three']);
 190          $comment = $this->get_comment_object($context, $ge3->id);
 191          $comment->add('User 2 comment');
 192  
 193          $this->plugingenerator->create_category($this->glossary, ['cat1'], [$ge3]);
 194          $count = $DB->count_records('glossary_entries_categories', ['entryid' => $ge3->id]);
 195          $this->assertEquals(1, $count);
 196          core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge3->id, $context, ['Pizza', 'Noodles']);
 197  
 198          // As a teacher, rate student 2 entry.
 199          $this->setUser($this->teacher);
 200          $rating = $this->get_rating_object($context, $ge3->id);
 201          $rating->update_rating(2);
 202  
 203          // Before deletion, we should have 2 entries.
 204          $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]);
 205          $this->assertEquals(2, $count);
 206          $aliascount = $DB->count_records('glossary_alias');
 207          $this->assertEquals(2, $aliascount);
 208          // Delete data based on context.
 209          provider::delete_data_for_all_users_in_context($context);
 210  
 211          // After deletion, the glossary entries and aliases for that glossary activity should have been deleted.
 212          $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]);
 213          $this->assertEquals(0, $count);
 214          $this->assertEquals(0, $DB->count_records('glossary_alias'));
 215          $count = $DB->count_records('glossary_entries_categories', ['entryid' => $ge3->id]);
 216          $this->assertEquals(0, $count);
 217          $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries',
 218              'itemid' => $ge3->id]);
 219          $this->assertEquals(0, $tagcount);
 220  
 221          $commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry',
 222              'itemid' => $ge3->id, 'userid' => $student2->id]);
 223          $this->assertEquals(0, $commentcount);
 224  
 225          $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry',
 226              'itemid' => $ge3->id]);
 227          $this->assertEquals(0, $ratingcount);
 228      }
 229  
 230      /**
 231       * Test for provider::delete_data_for_user().
 232       */
 233      public function test_delete_data_for_user() {
 234          global $DB;
 235          $generator = $this->getDataGenerator();
 236  
 237          // Create another student who will add an entry to the first glossary.
 238          $student2 = $generator->create_user();
 239          $generator->enrol_user($student2->id, $this->course->id, 'student');
 240  
 241          $cm1 = get_coursemodule_from_instance('glossary', $this->glossary->id);
 242          $glossary2 = $this->plugingenerator->create_instance(['course' => $this->course->id]);
 243          $cm2 = get_coursemodule_from_instance('glossary', $glossary2->id);
 244  
 245          $ge1 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'first user glossary entry', 'approved' => 1]);
 246          $this->plugingenerator->create_content($glossary2, ['concept' => 'first user second glossary entry', 'approved' => 1]);
 247  
 248          $context1 = context_module::instance($cm1->id);
 249          $context2 = context_module::instance($cm2->id);
 250          core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge1->id, $context1, ['Parmi', 'Sushi']);
 251  
 252          $this->setUser($student2);
 253          $ge3 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'second user glossary entry',
 254                  'approved' => 1], ['three']);
 255  
 256          $comment = $this->get_comment_object($context1, $ge3->id);
 257          $comment->add('User 2 comment');
 258  
 259          core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge3->id, $context1, ['Pizza', 'Noodles']);
 260  
 261          // As a teacher, rate student 2's entry.
 262          $this->setUser($this->teacher);
 263          $rating = $this->get_rating_object($context1, $ge3->id);
 264          $rating->update_rating(2);
 265  
 266          // Before deletion, we should have 3 entries, one rating and 2 tag instances.
 267          $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]);
 268          $this->assertEquals(3, $count);
 269          $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries',
 270              'itemid' => $ge3->id]);
 271          $this->assertEquals(2, $tagcount);
 272          $aliascount = $DB->count_records('glossary_alias', ['entryid' => $ge3->id]);
 273          $this->assertEquals(1, $aliascount);
 274          $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry',
 275              'itemid' => $ge3->id]);
 276          $this->assertEquals(1, $ratingcount);
 277  
 278          $contextlist = new \core_privacy\local\request\approved_contextlist($student2, 'glossary',
 279              [$context1->id, $context2->id]);
 280          provider::delete_data_for_user($contextlist);
 281  
 282          // After deletion, the glossary entry and tags for the second student should have been deleted.
 283          $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id, 'userid' => $student2->id]);
 284          $this->assertEquals(0, $count);
 285  
 286          $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries',
 287                  'itemid' => $ge3->id]);
 288          $this->assertEquals(0, $tagcount);
 289  
 290          $commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry',
 291                  'itemid' => $ge3->id, 'userid' => $student2->id]);
 292          $this->assertEquals(0, $commentcount);
 293          $aliascount = $DB->count_records('glossary_alias', ['entryid' => $ge3->id]);
 294          $this->assertEquals(0, $aliascount);
 295  
 296          // Student's 1 entries, comments and tags should not be removed.
 297          $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id,
 298                  'userid' => $this->student->id]);
 299          $this->assertEquals(2, $count);
 300  
 301          $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries',
 302              'itemid' => $ge1->id]);
 303          $this->assertEquals(2, $tagcount);
 304  
 305          $commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry',
 306               'userid' => $this->student->id]);
 307          $this->assertEquals(1, $commentcount);
 308  
 309          $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry',
 310              'itemid' => $ge3->id]);
 311          $this->assertEquals(0, $ratingcount);
 312      }
 313  
 314      /**
 315       * Test for provider::delete_data_for_users().
 316       */
 317      public function test_delete_data_for_users() {
 318          global $DB;
 319          $generator = $this->getDataGenerator();
 320  
 321          $student2 = $generator->create_user();
 322          $generator->enrol_user($student2->id, $this->course->id, 'student');
 323  
 324          $cm1 = get_coursemodule_from_instance('glossary', $this->glossary->id);
 325          $glossary2 = $this->plugingenerator->create_instance(['course' => $this->course->id]);
 326          $cm2 = get_coursemodule_from_instance('glossary', $glossary2->id);
 327  
 328          $ge1 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'first user glossary entry', 'approved' => 1]);
 329          $ge2 = $this->plugingenerator->create_content($glossary2, ['concept' => 'first user second glossary entry',
 330                  'approved' => 1], ['two']);
 331  
 332          $context1 = context_module::instance($cm1->id);
 333          $context2 = context_module::instance($cm2->id);
 334          core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge1->id, $context1, ['Parmi', 'Sushi']);
 335  
 336          $this->setUser($student2);
 337          $ge3 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'second user glossary entry',
 338                  'approved' => 1], ['three']);
 339  
 340          $comment = $this->get_comment_object($context1, $ge3->id);
 341          $comment->add('User 2 comment 1');
 342          $comment = $this->get_comment_object($context2, $ge2->id);
 343          $comment->add('User 2 comment 2');
 344  
 345          core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge3->id, $context1, ['Pizza', 'Noodles']);
 346          core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge2->id, $context2, ['Potato', 'Kumara']);
 347  
 348          // As a teacher, rate student 2's entry.
 349          $this->setUser($this->teacher);
 350          $rating = $this->get_rating_object($context1, $ge3->id);
 351          $rating->update_rating(2);
 352  
 353          // Check correct glossary 1 record counts before deletion.
 354          $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]);
 355          // Note: There is an additional student entry from setUp().
 356          $this->assertEquals(3, $count);
 357  
 358          list($context1itemsql, $context1itemparams) = $DB->get_in_or_equal([$ge1->id, $ge3->id], SQL_PARAMS_NAMED);
 359          $geparams = [
 360              'component' => 'mod_glossary',
 361              'itemtype' => 'glossary_entries',
 362          ];
 363          $geparams += $context1itemparams;
 364          $wheresql = "component = :component AND itemtype = :itemtype AND itemid {$context1itemsql}";
 365  
 366          $tagcount = $DB->count_records_select('tag_instance', $wheresql, $geparams);
 367          $this->assertEquals(4, $tagcount);
 368  
 369          $aliascount = $DB->count_records_select('glossary_alias', "entryid {$context1itemsql}", $context1itemparams);
 370          $this->assertEquals(1, $aliascount);
 371  
 372          $commentparams = [
 373              'component' => 'mod_glossary',
 374              'commentarea' => 'glossary_entry',
 375          ];
 376          $commentparams += $context1itemparams;
 377          $commentwhere = "component = :component AND commentarea = :commentarea AND itemid {$context1itemsql}";
 378  
 379          $commentcount = $DB->count_records_select('comments', $commentwhere, $commentparams);
 380          $this->assertEquals(1, $commentcount);
 381  
 382          $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry',
 383              'itemid' => $ge3->id]);
 384          $this->assertEquals(1, $ratingcount);
 385  
 386          // Perform deletion within context 1 for both students.
 387          $approveduserlist = new core_privacy\local\request\approved_userlist($context1, 'mod_glossary',
 388                  [$this->student->id, $student2->id]);
 389          provider::delete_data_for_users($approveduserlist);
 390  
 391          // After deletion, all context 1 entries, tags and comment should be deleted.
 392          $count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]);
 393          $this->assertEquals(0, $count);
 394  
 395          $tagcount = $DB->count_records_select('tag_instance', $wheresql, $geparams);
 396          $this->assertEquals(0, $tagcount);
 397  
 398          $aliascount = $DB->count_records_select('glossary_alias', "entryid {$context1itemsql}", $context1itemparams);
 399          $this->assertEquals(0, $aliascount);
 400  
 401          $commentcount = $DB->count_records_select('comments', $commentwhere, $commentparams);
 402          $this->assertEquals(0, $commentcount);
 403  
 404          // Context 2 entries should remain intact.
 405          $count = $DB->count_records('glossary_entries', ['glossaryid' => $glossary2->id]);
 406          $this->assertEquals(1, $count);
 407  
 408          $tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries',
 409                  'itemid' => $ge2->id]);
 410          $this->assertEquals(2, $tagcount);
 411  
 412          $aliascount = $DB->count_records('glossary_alias', ['entryid' => $ge2->id]);
 413          $this->assertEquals(1, $aliascount);
 414  
 415          $commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry',
 416               'itemid' => $ge2->id]);
 417          $this->assertEquals(1, $commentcount);
 418  
 419          $ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry',
 420              'itemid' => $ge3->id]);
 421          $this->assertEquals(0, $ratingcount);
 422      }
 423  
 424      /**
 425       * Get the comment area for glossary module.
 426       *
 427       * @param context $context The context.
 428       * @param int $itemid The item ID.
 429       * @return comment
 430       */
 431      protected function get_comment_object(context $context, $itemid) {
 432          $args = new stdClass();
 433  
 434          $args->context = $context;
 435          $args->course = get_course(SITEID);
 436          $args->area = 'glossary_entry';
 437          $args->itemid = $itemid;
 438          $args->component = 'mod_glossary';
 439          $comment = new comment($args);
 440          $comment->set_post_permission(true);
 441  
 442          return $comment;
 443      }
 444  
 445      /**
 446       * Get the rating area for glossary module.
 447       *
 448       * @param context $context The context.
 449       * @param int $itemid The item ID.
 450       * @return rating object
 451       */
 452      protected function get_rating_object(context $context, $itemid) {
 453          global $USER;
 454  
 455          $ratingoptions = new stdClass;
 456          $ratingoptions->context = $context;
 457          $ratingoptions->ratingarea = 'entry';
 458          $ratingoptions->component = 'mod_glossary';
 459          $ratingoptions->itemid  = $itemid;
 460          $ratingoptions->scaleid = 2;
 461          $ratingoptions->userid  = $USER->id;
 462          return new rating($ratingoptions);
 463      }
 464  }