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