Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 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.
   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_lti
  21   * @copyright  2018 Mark Nelson <markn@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 mod_lti\privacy\provider;
  27  
  28  defined('MOODLE_INTERNAL') || die();
  29  
  30  /**
  31   * Privacy provider tests class.
  32   *
  33   * @package    mod_lti
  34   * @copyright  2018 Mark Nelson <markn@moodle.com>
  35   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class mod_lti_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
  38  
  39      /**
  40       * Test for provider::get_metadata().
  41       */
  42      public function test_get_metadata() {
  43          $collection = new collection('mod_lti');
  44          $newcollection = provider::get_metadata($collection);
  45          $itemcollection = $newcollection->get_collection();
  46          $this->assertCount(4, $itemcollection);
  47  
  48          $ltiproviderexternal = array_shift($itemcollection);
  49          $this->assertEquals('lti_provider', $ltiproviderexternal->get_name());
  50  
  51          $ltisubmissiontable = array_shift($itemcollection);
  52          $this->assertEquals('lti_submission', $ltisubmissiontable->get_name());
  53  
  54          $ltitoolproxies = array_shift($itemcollection);
  55          $this->assertEquals('lti_tool_proxies', $ltitoolproxies->get_name());
  56  
  57          $ltitypestable = array_shift($itemcollection);
  58          $this->assertEquals('lti_types', $ltitypestable->get_name());
  59  
  60          $privacyfields = $ltisubmissiontable->get_privacy_fields();
  61          $this->assertArrayHasKey('userid', $privacyfields);
  62          $this->assertArrayHasKey('datesubmitted', $privacyfields);
  63          $this->assertArrayHasKey('dateupdated', $privacyfields);
  64          $this->assertArrayHasKey('gradepercent', $privacyfields);
  65          $this->assertArrayHasKey('originalgrade', $privacyfields);
  66          $this->assertEquals('privacy:metadata:lti_submission', $ltisubmissiontable->get_summary());
  67  
  68          $privacyfields = $ltitoolproxies->get_privacy_fields();
  69          $this->assertArrayHasKey('name', $privacyfields);
  70          $this->assertArrayHasKey('createdby', $privacyfields);
  71          $this->assertArrayHasKey('timecreated', $privacyfields);
  72          $this->assertArrayHasKey('timemodified', $privacyfields);
  73          $this->assertEquals('privacy:metadata:lti_tool_proxies', $ltitoolproxies->get_summary());
  74  
  75          $privacyfields = $ltitypestable->get_privacy_fields();
  76          $this->assertArrayHasKey('name', $privacyfields);
  77          $this->assertArrayHasKey('createdby', $privacyfields);
  78          $this->assertArrayHasKey('timecreated', $privacyfields);
  79          $this->assertArrayHasKey('timemodified', $privacyfields);
  80          $this->assertEquals('privacy:metadata:lti_types', $ltitypestable->get_summary());
  81      }
  82  
  83      /**
  84       * Test for provider::get_contexts_for_userid().
  85       */
  86      public function test_get_contexts_for_userid() {
  87          $this->resetAfterTest();
  88  
  89          $course = $this->getDataGenerator()->create_course();
  90  
  91          // The LTI activity the user will have submitted something for.
  92          $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
  93  
  94          // Another LTI activity that has no user activity.
  95          $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
  96  
  97          // Create a user which will make a submission.
  98          $user = $this->getDataGenerator()->create_user();
  99  
 100          $this->create_lti_submission($lti->id, $user->id);
 101  
 102          // Check the contexts supplied are correct.
 103          $contextlist = provider::get_contexts_for_userid($user->id);
 104          $this->assertCount(2, $contextlist);
 105  
 106          $contextformodule = $contextlist->current();
 107          $cmcontext = context_module::instance($lti->cmid);
 108          $this->assertEquals($cmcontext->id, $contextformodule->id);
 109  
 110          $contextlist->next();
 111          $contextforsystem = $contextlist->current();
 112          $this->assertEquals(SYSCONTEXTID, $contextforsystem->id);
 113      }
 114  
 115      /**
 116       * Test for provider::test_get_users_in_context()
 117       */
 118      public function test_get_users_in_context() {
 119          $this->resetAfterTest();
 120  
 121          $course = $this->getDataGenerator()->create_course();
 122          $component = 'mod_lti';
 123  
 124          // The LTI activity the user will have submitted something for.
 125          $lti1 = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
 126  
 127          // Another LTI activity that has no user activity.
 128          $lti2 = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
 129  
 130          // Create user which will make a submission each.
 131          $user1 = $this->getDataGenerator()->create_user();
 132          $user2 = $this->getDataGenerator()->create_user();
 133  
 134          $this->create_lti_submission($lti1->id, $user1->id);
 135          $this->create_lti_submission($lti1->id, $user2->id);
 136  
 137          $context = context_module::instance($lti1->cmid);
 138          $userlist = new \core_privacy\local\request\userlist($context, $component);
 139          provider::get_users_in_context($userlist);
 140  
 141          $this->assertCount(2, $userlist);
 142          $expected = [$user1->id, $user2->id];
 143          $actual = $userlist->get_userids();
 144          sort($expected);
 145          sort($actual);
 146  
 147          $this->assertEquals($expected, $actual);
 148  
 149          $context = context_module::instance($lti2->cmid);
 150          $userlist = new \core_privacy\local\request\userlist($context, $component);
 151          provider::get_users_in_context($userlist);
 152  
 153          $this->assertEmpty($userlist);
 154      }
 155  
 156      /**
 157       * Test for provider::export_user_data().
 158       */
 159      public function test_export_for_context_submissions() {
 160          $this->resetAfterTest();
 161  
 162          $course = $this->getDataGenerator()->create_course();
 163  
 164          $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
 165  
 166          // Create users which will make submissions.
 167          $user1 = $this->getDataGenerator()->create_user();
 168          $user2 = $this->getDataGenerator()->create_user();
 169  
 170          $this->create_lti_submission($lti->id, $user1->id);
 171          $this->create_lti_submission($lti->id, $user1->id);
 172          $this->create_lti_submission($lti->id, $user2->id);
 173  
 174          // Export all of the data for the context for user 1.
 175          $cmcontext = context_module::instance($lti->cmid);
 176          $this->export_context_data_for_user($user1->id, $cmcontext, 'mod_lti');
 177          $writer = \core_privacy\local\request\writer::with_context($cmcontext);
 178  
 179          $this->assertTrue($writer->has_any_data());
 180  
 181          $data = $writer->get_data();
 182          $this->assertCount(2, $data->submissions);
 183      }
 184  
 185      /**
 186       * Test for provider::export_user_data().
 187       */
 188      public function test_export_for_context_tool_types() {
 189          $this->resetAfterTest();
 190  
 191          $course1 = $this->getDataGenerator()->create_course();
 192          $course2 = $this->getDataGenerator()->create_course();
 193  
 194          // Create a user which will make a tool type.
 195          $user = $this->getDataGenerator()->create_user();
 196          $this->setUser($user);
 197  
 198          // Create a user that will not make a tool type.
 199          $this->getDataGenerator()->create_user();
 200  
 201          $type = new stdClass();
 202          $type->baseurl = 'http://moodle.org';
 203          $type->course = $course1->id;
 204          lti_add_type($type, new stdClass());
 205  
 206          $type = new stdClass();
 207          $type->baseurl = 'http://moodle.org';
 208          $type->course = $course1->id;
 209          lti_add_type($type, new stdClass());
 210  
 211          $type = new stdClass();
 212          $type->baseurl = 'http://moodle.org';
 213          $type->course = $course2->id;
 214          lti_add_type($type, new stdClass());
 215  
 216          // Export all of the data for the context.
 217          $coursecontext = context_course::instance($course1->id);
 218          $this->export_context_data_for_user($user->id, $coursecontext, 'mod_lti');
 219          $writer = \core_privacy\local\request\writer::with_context($coursecontext);
 220  
 221          $this->assertTrue($writer->has_any_data());
 222  
 223          $data = $writer->get_data();
 224          $this->assertCount(2, $data->lti_types);
 225  
 226          $coursecontext = context_course::instance($course2->id);
 227          $this->export_context_data_for_user($user->id, $coursecontext, 'mod_lti');
 228          $writer = \core_privacy\local\request\writer::with_context($coursecontext);
 229  
 230          $this->assertTrue($writer->has_any_data());
 231  
 232          $data = $writer->get_data();
 233          $this->assertCount(1, $data->lti_types);
 234      }
 235  
 236      /**
 237       * Test for provider::export_user_data().
 238       */
 239      public function test_export_for_context_tool_proxies() {
 240          $this->resetAfterTest();
 241  
 242          // Create a user that will not make a tool proxy.
 243          $user = $this->getDataGenerator()->create_user();
 244          $this->setUser($user);
 245  
 246          $toolproxy = new stdClass();
 247          $toolproxy->createdby = $user;
 248          lti_add_tool_proxy($toolproxy);
 249  
 250          // Export all of the data for the context.
 251          $systemcontext = context_system::instance();
 252          $this->export_context_data_for_user($user->id, $systemcontext, 'mod_lti');
 253          $writer = \core_privacy\local\request\writer::with_context($systemcontext);
 254  
 255          $this->assertTrue($writer->has_any_data());
 256  
 257          $data = $writer->get_data();
 258          $this->assertCount(1, $data->lti_tool_proxies);
 259      }
 260  
 261      /**
 262       * Test for provider::delete_data_for_all_users_in_context().
 263       */
 264      public function test_delete_data_for_all_users_in_context() {
 265          global $DB;
 266  
 267          $this->resetAfterTest();
 268  
 269          $course = $this->getDataGenerator()->create_course();
 270  
 271          $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
 272  
 273          // Create users that will make submissions.
 274          $user1 = $this->getDataGenerator()->create_user();
 275          $user2 = $this->getDataGenerator()->create_user();
 276  
 277          $this->create_lti_submission($lti->id, $user1->id);
 278          $this->create_lti_submission($lti->id, $user2->id);
 279  
 280          // Before deletion, we should have 2 responses.
 281          $count = $DB->count_records('lti_submission', ['ltiid' => $lti->id]);
 282          $this->assertEquals(2, $count);
 283  
 284          // Delete data based on context.
 285          $cmcontext = context_module::instance($lti->cmid);
 286          provider::delete_data_for_all_users_in_context($cmcontext);
 287  
 288          // After deletion, the lti submissions for that lti activity should have been deleted.
 289          $count = $DB->count_records('lti_submission', ['ltiid' => $lti->id]);
 290          $this->assertEquals(0, $count);
 291      }
 292  
 293      /**
 294       * Test for provider::delete_data_for_user().
 295       */
 296      public function test_delete_data_for_user() {
 297          global $DB;
 298  
 299          $this->resetAfterTest();
 300  
 301          $course = $this->getDataGenerator()->create_course();
 302  
 303          $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
 304  
 305          // Create users that will make submissions.
 306          $user1 = $this->getDataGenerator()->create_user();
 307          $user2 = $this->getDataGenerator()->create_user();
 308  
 309          $this->create_lti_submission($lti->id, $user1->id);
 310          $this->create_lti_submission($lti->id, $user2->id);
 311  
 312          // Before deletion we should have 2 responses.
 313          $count = $DB->count_records('lti_submission', ['ltiid' => $lti->id]);
 314          $this->assertEquals(2, $count);
 315  
 316          $context = \context_module::instance($lti->cmid);
 317          $contextlist = new \core_privacy\local\request\approved_contextlist($user1, 'lti',
 318              [context_system::instance()->id, $context->id]);
 319          provider::delete_data_for_user($contextlist);
 320  
 321          // After deletion the lti submission for the first user should have been deleted.
 322          $count = $DB->count_records('lti_submission', ['ltiid' => $lti->id, 'userid' => $user1->id]);
 323          $this->assertEquals(0, $count);
 324  
 325          // Check the submission for the other user is still there.
 326          $ltisubmission = $DB->get_records('lti_submission');
 327          $this->assertCount(1, $ltisubmission);
 328          $lastsubmission = reset($ltisubmission);
 329          $this->assertEquals($user2->id, $lastsubmission->userid);
 330      }
 331  
 332      /**
 333       * Test for provider::delete_data_for_users().
 334       */
 335      public function test_delete_data_for_users() {
 336          global $DB;
 337          $component = 'mod_lti';
 338  
 339          $this->resetAfterTest();
 340  
 341          $course = $this->getDataGenerator()->create_course();
 342  
 343          $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
 344  
 345          // Create users that will make submissions.
 346          $user1 = $this->getDataGenerator()->create_user();
 347          $user2 = $this->getDataGenerator()->create_user();
 348          $user3 = $this->getDataGenerator()->create_user();
 349  
 350          $this->create_lti_submission($lti->id, $user1->id);
 351          $this->create_lti_submission($lti->id, $user2->id);
 352          $this->create_lti_submission($lti->id, $user3->id);
 353  
 354          // Before deletion we should have 2 responses.
 355          $count = $DB->count_records('lti_submission', ['ltiid' => $lti->id]);
 356          $this->assertEquals(3, $count);
 357  
 358          $context = \context_module::instance($lti->cmid);
 359          $approveduserids = [$user1->id, $user2->id];
 360          $approvedlist = new core_privacy\local\request\approved_userlist($context, $component, $approveduserids);
 361          provider::delete_data_for_users($approvedlist);
 362  
 363          // After deletion the lti submission for the first two users should have been deleted.
 364          list($insql, $inparams) = $DB->get_in_or_equal($approveduserids, SQL_PARAMS_NAMED);
 365          $sql = "ltiid = :ltiid AND userid {$insql}";
 366          $params = array_merge($inparams, ['ltiid' => $lti->id]);
 367          $count = $DB->count_records_select('lti_submission', $sql, $params);
 368          $this->assertEquals(0, $count);
 369  
 370          // Check the submission for the third user is still there.
 371          $ltisubmission = $DB->get_records('lti_submission');
 372          $this->assertCount(1, $ltisubmission);
 373          $lastsubmission = reset($ltisubmission);
 374          $this->assertEquals($user3->id, $lastsubmission->userid);
 375      }
 376  
 377      /**
 378       * Mimicks the creation of an LTI submission.
 379       *
 380       * There is no API we can use to insert an LTI submission, so we
 381       * will simply insert directly into the database.
 382       *
 383       * @param int $ltiid
 384       * @param int $userid
 385       */
 386      protected function create_lti_submission(int $ltiid, int $userid) {
 387          global $DB;
 388  
 389          $ltisubmissiondata = [
 390              'ltiid' => $ltiid,
 391              'userid' => $userid,
 392              'datesubmitted' => time(),
 393              'dateupdated' => time(),
 394              'gradepercent' => 65,
 395              'originalgrade' => 70,
 396              'launchid' => 3,
 397              'state' => 1
 398          ];
 399  
 400          $DB->insert_record('lti_submission', $ltisubmissiondata);
 401      }
 402  }