MDL-63498 mod_lti: Add support for removal of context users
[moodle.git] / mod / lti / tests / privacy_provider_test.php
blobede951f710cd8a02afe2be0eee61cc95db4529b8
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.
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/>.
17 /**
18 * Privacy provider tests.
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
25 use core_privacy\local\metadata\collection;
26 use mod_lti\privacy\provider;
28 defined('MOODLE_INTERNAL') || die();
30 /**
31 * Privacy provider tests class.
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
37 class mod_lti_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
39 /**
40 * Test for provider::get_metadata().
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);
48 $ltiproviderexternal = array_shift($itemcollection);
49 $this->assertEquals('lti_provider', $ltiproviderexternal->get_name());
51 $ltisubmissiontable = array_shift($itemcollection);
52 $this->assertEquals('lti_submission', $ltisubmissiontable->get_name());
54 $ltitoolproxies = array_shift($itemcollection);
55 $this->assertEquals('lti_tool_proxies', $ltitoolproxies->get_name());
57 $ltitypestable = array_shift($itemcollection);
58 $this->assertEquals('lti_types', $ltitypestable->get_name());
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());
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());
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());
83 /**
84 * Test for provider::get_contexts_for_userid().
86 public function test_get_contexts_for_userid() {
87 $this->resetAfterTest();
89 $course = $this->getDataGenerator()->create_course();
91 // The LTI activity the user will have submitted something for.
92 $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
94 // Another LTI activity that has no user activity.
95 $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
97 // Create a user which will make a submission.
98 $user = $this->getDataGenerator()->create_user();
100 $this->create_lti_submission($lti->id, $user->id);
102 // Check the contexts supplied are correct.
103 $contextlist = provider::get_contexts_for_userid($user->id);
104 $this->assertCount(2, $contextlist);
106 $contextformodule = $contextlist->current();
107 $cmcontext = context_module::instance($lti->cmid);
108 $this->assertEquals($cmcontext->id, $contextformodule->id);
110 $contextlist->next();
111 $contextforsystem = $contextlist->current();
112 $this->assertEquals(SYSCONTEXTID, $contextforsystem->id);
116 * Test for provider::test_get_users_in_context()
118 public function test_get_users_in_context() {
119 $this->resetAfterTest();
121 $course = $this->getDataGenerator()->create_course();
122 $component = 'mod_lti';
124 // The LTI activity the user will have submitted something for.
125 $lti1 = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
127 // Another LTI activity that has no user activity.
128 $lti2 = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
130 // Create user which will make a submission each.
131 $user1 = $this->getDataGenerator()->create_user();
132 $user2 = $this->getDataGenerator()->create_user();
134 $this->create_lti_submission($lti1->id, $user1->id);
135 $this->create_lti_submission($lti1->id, $user2->id);
137 $context = context_module::instance($lti1->cmid);
138 $userlist = new \core_privacy\local\request\userlist($context, $component);
139 provider::get_users_in_context($userlist);
141 $this->assertCount(2, $userlist);
142 $expected = [$user1->id, $user2->id];
143 $actual = $userlist->get_userids();
144 sort($expected);
145 sort($actual);
147 $this->assertEquals($expected, $actual);
149 $context = context_module::instance($lti2->cmid);
150 $userlist = new \core_privacy\local\request\userlist($context, $component);
151 provider::get_users_in_context($userlist);
153 $this->assertEmpty($userlist);
157 * Test for provider::export_user_data().
159 public function test_export_for_context_submissions() {
160 $this->resetAfterTest();
162 $course = $this->getDataGenerator()->create_course();
164 $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
166 // Create users which will make submissions.
167 $user1 = $this->getDataGenerator()->create_user();
168 $user2 = $this->getDataGenerator()->create_user();
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);
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);
179 $this->assertTrue($writer->has_any_data());
181 $data = $writer->get_data();
182 $this->assertCount(2, $data->submissions);
186 * Test for provider::export_user_data().
188 public function test_export_for_context_tool_types() {
189 $this->resetAfterTest();
191 $course1 = $this->getDataGenerator()->create_course();
192 $course2 = $this->getDataGenerator()->create_course();
194 // Create a user which will make a tool type.
195 $user = $this->getDataGenerator()->create_user();
196 $this->setUser($user);
198 // Create a user that will not make a tool type.
199 $this->getDataGenerator()->create_user();
201 $type = new stdClass();
202 $type->baseurl = 'http://moodle.org';
203 $type->course = $course1->id;
204 lti_add_type($type, new stdClass());
206 $type = new stdClass();
207 $type->baseurl = 'http://moodle.org';
208 $type->course = $course1->id;
209 lti_add_type($type, new stdClass());
211 $type = new stdClass();
212 $type->baseurl = 'http://moodle.org';
213 $type->course = $course2->id;
214 lti_add_type($type, new stdClass());
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);
221 $this->assertTrue($writer->has_any_data());
223 $data = $writer->get_data();
224 $this->assertCount(2, $data->lti_types);
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);
230 $this->assertTrue($writer->has_any_data());
232 $data = $writer->get_data();
233 $this->assertCount(1, $data->lti_types);
237 * Test for provider::export_user_data().
239 public function test_export_for_context_tool_proxies() {
240 $this->resetAfterTest();
242 // Create a user that will not make a tool proxy.
243 $user = $this->getDataGenerator()->create_user();
244 $this->setUser($user);
246 $toolproxy = new stdClass();
247 $toolproxy->createdby = $user;
248 lti_add_tool_proxy($toolproxy);
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);
255 $this->assertTrue($writer->has_any_data());
257 $data = $writer->get_data();
258 $this->assertCount(1, $data->lti_tool_proxies);
262 * Test for provider::delete_data_for_all_users_in_context().
264 public function test_delete_data_for_all_users_in_context() {
265 global $DB;
267 $this->resetAfterTest();
269 $course = $this->getDataGenerator()->create_course();
271 $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
273 // Create users that will make submissions.
274 $user1 = $this->getDataGenerator()->create_user();
275 $user2 = $this->getDataGenerator()->create_user();
277 $this->create_lti_submission($lti->id, $user1->id);
278 $this->create_lti_submission($lti->id, $user2->id);
280 // Before deletion, we should have 2 responses.
281 $count = $DB->count_records('lti_submission', ['ltiid' => $lti->id]);
282 $this->assertEquals(2, $count);
284 // Delete data based on context.
285 $cmcontext = context_module::instance($lti->cmid);
286 provider::delete_data_for_all_users_in_context($cmcontext);
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);
294 * Test for provider::delete_data_for_user().
296 public function test_delete_data_for_user() {
297 global $DB;
299 $this->resetAfterTest();
301 $course = $this->getDataGenerator()->create_course();
303 $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
305 // Create users that will make submissions.
306 $user1 = $this->getDataGenerator()->create_user();
307 $user2 = $this->getDataGenerator()->create_user();
309 $this->create_lti_submission($lti->id, $user1->id);
310 $this->create_lti_submission($lti->id, $user2->id);
312 // Before deletion we should have 2 responses.
313 $count = $DB->count_records('lti_submission', ['ltiid' => $lti->id]);
314 $this->assertEquals(2, $count);
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);
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);
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);
333 * Test for provider::delete_data_for_users().
335 public function test_delete_data_for_users() {
336 global $DB;
337 $component = 'mod_lti';
339 $this->resetAfterTest();
341 $course = $this->getDataGenerator()->create_course();
343 $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id));
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();
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);
354 // Before deletion we should have 2 responses.
355 $count = $DB->count_records('lti_submission', ['ltiid' => $lti->id]);
356 $this->assertEquals(3, $count);
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);
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);
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);
378 * Mimicks the creation of an LTI submission.
380 * There is no API we can use to insert an LTI submission, so we
381 * will simply insert directly into the database.
383 * @param int $ltiid
384 * @param int $userid
386 protected function create_lti_submission(int $ltiid, int $userid) {
387 global $DB;
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
400 $DB->insert_record('lti_submission', $ltisubmissiondata);