MDL-63688 core_tag: Add method that returns users in context
[moodle.git] / tag / tests / privacy_test.php
CommitLineData
e4f6c0c2
ZT
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 tests for core_tag.
19 *
20 * @package core_comment
21 * @category test
22 * @copyright 2018 Zig Tan <zig@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die();
27global $CFG;
28
29require_once($CFG->dirroot . '/tag/lib.php');
30
31use \core_privacy\tests\provider_testcase;
32use \core_privacy\local\request\writer;
33use \core_tag\privacy\provider;
1d3d4c66 34use \core_privacy\local\request\approved_userlist;
e4f6c0c2
ZT
35
36/**
37 * Unit tests for tag/classes/privacy/policy
38 *
39 * @copyright 2018 Zig Tan <zig@moodle.com>
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 */
42class core_tag_privacy_testcase extends provider_testcase {
43
44 /**
45 * Check the exporting of tags for a user id in a context.
46 */
47 public function test_export_tags() {
48 global $DB;
49
50 $this->resetAfterTest(true);
51
52 // Create a user to perform tagging.
53 $user = $this->getDataGenerator()->create_user();
54 $this->setUser($user);
55
56 // Create a course to tag.
57 $course = $this->getDataGenerator()->create_course();
58 $context = context_course::instance($course->id);
59 $subcontext = [];
60
61 // Create three dummy tags and tag instances.
62 $dummytags = [ 'Tag 1', 'Tag 2', 'Tag 3' ];
63 core_tag_tag::set_item_tags('core_course', 'course', $course->id, context_course::instance($course->id),
64 $dummytags, $user->id);
65
66 // Get the tag instances that should have been created.
67 $taginstances = $DB->get_records('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id));
68 $this->assertCount(count($dummytags), $taginstances);
69
70 // Check tag instances match the component and context.
71 foreach ($taginstances as $taginstance) {
72 $this->assertEquals('core_course', $taginstance->component);
73 $this->assertEquals(context_course::instance($course->id)->id, $taginstance->contextid);
74 }
75
76 // Retrieve tags only for this user.
77 provider::export_item_tags($user->id, $context, $subcontext, 'core_course', 'course', $course->id, true);
78
79 $writer = writer::with_context($context);
80 $this->assertTrue($writer->has_any_data());
81
82 $exportedtags = $writer->get_related_data($subcontext, 'tags');
83 $this->assertCount(count($dummytags), $exportedtags);
84
85 // Check the exported tag's rawname is found in the initial dummy tags.
86 foreach ($exportedtags as $exportedtag) {
2207b0fa 87 $this->assertContains($exportedtag, $dummytags);
e4f6c0c2
ZT
88 }
89 }
1c4b87cb
MG
90
91 /**
92 * Test method delete_item_tags().
93 */
94 public function test_delete_item_tags() {
95 global $DB;
96
97 $this->resetAfterTest(true);
98
99 // Create a course to tag.
100 $course1 = $this->getDataGenerator()->create_course();
101 $context1 = context_course::instance($course1->id);
102 $course2 = $this->getDataGenerator()->create_course();
103 $context2 = context_course::instance($course2->id);
104
105 // Tag courses.
106 core_tag_tag::set_item_tags('core_course', 'course', $course1->id, $context1, ['Tag 1', 'Tag 2', 'Tag 3']);
107 core_tag_tag::set_item_tags('core_course', 'course', $course2->id, $context2, ['Tag 1', 'Tag 2']);
108
109 $expectedtagcount = $DB->count_records('tag_instance');
110 // Delete tags for course1.
111 core_tag\privacy\provider::delete_item_tags($context1, 'core_course', 'course');
112 $expectedtagcount -= 3;
113 $this->assertEquals($expectedtagcount, $DB->count_records('tag_instance'));
114
115 // Delete tags for course2. Use wrong itemid.
116 core_tag\privacy\provider::delete_item_tags($context2, 'core_course', 'course', $course1->id);
117 $this->assertEquals($expectedtagcount, $DB->count_records('tag_instance'));
118
119 // Use correct itemid.
120 core_tag\privacy\provider::delete_item_tags($context2, 'core_course', 'course', $course2->id);
121 $expectedtagcount -= 2;
122 $this->assertEquals($expectedtagcount, $DB->count_records('tag_instance'));
123 }
124
af2e8ed9
HN
125 /**
126 * Test method delete_item_tags() with userid.
127 */
128 public function test_delete_item_tags_with_userid() {
129 global $DB;
130
131 $this->resetAfterTest(true);
132 // Create a course to tag.
133 $course = $this->getDataGenerator()->create_course();
134 $context = context_course::instance($course->id);
135
136 // Create a user to perform tagging.
137 $user = $this->getDataGenerator()->create_user();
138 $this->setUser($user);
139
140 // Tag courses.
141 core_tag_tag::set_item_tags('core_course', 'course', $course->id, $context, ['Tag 1', 'Tag 2'], $user->id);
142 $expectedtagcount = $DB->count_records('tag_instance');
143
144 // Delete tags for course. Use wrong userid.
145 core_tag\privacy\provider::delete_item_tags($context, 'core_course', 'course', null, 1);
146 $this->assertEquals($expectedtagcount, $DB->count_records('tag_instance'));
147
148 $expectedtagcount -= 2;
149 // Delete tags for course. Use correct userid.
150 core_tag\privacy\provider::delete_item_tags($context, 'core_course', 'course', null, $user->id);
151 $this->assertEquals($expectedtagcount, $DB->count_records('tag_instance'));
152 }
153
1c4b87cb
MG
154 /**
155 * Test method delete_item_tags_select().
156 */
157 public function test_delete_item_tags_select() {
158 global $DB;
159
160 $this->resetAfterTest(true);
161
162 // Create a course to tag.
163 $course1 = $this->getDataGenerator()->create_course();
164 $context1 = context_course::instance($course1->id);
165 $course2 = $this->getDataGenerator()->create_course();
166 $context2 = context_course::instance($course2->id);
167
168 // Tag courses.
169 core_tag_tag::set_item_tags('core_course', 'course', $course1->id, $context1, ['Tag 1', 'Tag 2', 'Tag 3']);
170 core_tag_tag::set_item_tags('core_course', 'course', $course2->id, $context2, ['Tag 1', 'Tag 2']);
171
172 $expectedtagcount = $DB->count_records('tag_instance');
173 // Delete tags for course1.
174 list($sql, $params) = $DB->get_in_or_equal([$course1->id, $course2->id], SQL_PARAMS_NAMED);
175 core_tag\privacy\provider::delete_item_tags_select($context1, 'core_course', 'course', $sql, $params);
176 $expectedtagcount -= 3;
177 $this->assertEquals($expectedtagcount, $DB->count_records('tag_instance'));
178
179 // Delete tags for course2.
180 core_tag\privacy\provider::delete_item_tags_select($context2, 'core_course', 'course', $sql, $params);
181 $expectedtagcount -= 2;
182 $this->assertEquals($expectedtagcount, $DB->count_records('tag_instance'));
183 }
2207b0fa
MG
184
185 protected function set_up_tags() {
186 global $CFG;
187 require_once($CFG->dirroot.'/user/editlib.php');
188
189 $this->resetAfterTest(true);
190
191 $user1 = $this->getDataGenerator()->create_user();
192 $user2 = $this->getDataGenerator()->create_user();
193
194 $this->setUser($user1);
195 useredit_update_interests($user1, ['Birdwatching', 'Computers']);
196
197 $this->setUser($user2);
198 useredit_update_interests($user2, ['computers']);
199
200 $this->setAdminUser();
201
202 $tag = core_tag_tag::get_by_name(0, 'computers', '*');
203 $tag->update(['description' => '<img src="@@PLUGINFILE@@/computer.jpg">']);
204 get_file_storage()->create_file_from_string([
205 'contextid' => context_system::instance()->id,
206 'component' => 'tag',
207 'filearea' => 'description',
208 'itemid' => $tag->id,
209 'filepath' => '/',
210 'filename' => 'computer.jpg'
211 ], "jpg:image");
212
213 return [$user1, $user2];
214 }
215
216 public function test_export_item_tags() {
217 list($user1, $user2) = $this->set_up_tags();
218 $this->assertEquals([context_system::instance()->id],
219 provider::get_contexts_for_userid($user1->id)->get_contextids());
220 $this->assertEmpty(provider::get_contexts_for_userid($user2->id)->get_contextids());
221 }
222
223 public function test_delete_data_for_user() {
224 global $DB;
225 list($user1, $user2) = $this->set_up_tags();
226 $context = context_system::instance();
227 $this->assertEquals(2, $DB->count_records('tag', []));
228 $this->assertEquals(0, $DB->count_records('tag', ['userid' => 0]));
229 provider::delete_data_for_user(new \core_privacy\local\request\approved_contextlist($user2, 'core_tag', [$context->id]));
230 $this->assertEquals(2, $DB->count_records('tag', []));
231 $this->assertEquals(0, $DB->count_records('tag', ['userid' => 0]));
232 provider::delete_data_for_user(new \core_privacy\local\request\approved_contextlist($user1, 'core_tag', [$context->id]));
233 $this->assertEquals(2, $DB->count_records('tag', []));
234 $this->assertEquals(2, $DB->count_records('tag', ['userid' => 0]));
235 }
236
237 public function test_delete_data_for_all_users_in_context() {
238 global $DB;
239 $course = $this->getDataGenerator()->create_course();
240 list($user1, $user2) = $this->set_up_tags();
241 $this->assertEquals(2, $DB->count_records('tag', []));
242 $this->assertEquals(3, $DB->count_records('tag_instance', []));
243 provider::delete_data_for_all_users_in_context(context_course::instance($course->id));
244 $this->assertEquals(2, $DB->count_records('tag', []));
245 $this->assertEquals(3, $DB->count_records('tag_instance', []));
246 provider::delete_data_for_all_users_in_context(context_system::instance());
247 $this->assertEquals(0, $DB->count_records('tag', []));
248 $this->assertEquals(0, $DB->count_records('tag_instance', []));
249 }
250
251 public function test_export_data_for_user() {
252 global $DB;
253 list($user1, $user2) = $this->set_up_tags();
254 $context = context_system::instance();
255 provider::export_user_data(new \core_privacy\local\request\approved_contextlist($user2, 'core_tag', [$context->id]));
256 $this->assertFalse(writer::with_context($context)->has_any_data());
257
258 $tagids = array_values(array_map(function($tag) {
259 return $tag->id;
260 }, core_tag_tag::get_by_name_bulk(core_tag_collection::get_default(), ['Birdwatching', 'Computers'])));
261
262 provider::export_user_data(new \core_privacy\local\request\approved_contextlist($user1, 'core_tag', [$context->id]));
263 $writer = writer::with_context($context);
264
265 $data = $writer->get_data(['Tags', $tagids[0]]);
266 $files = $writer->get_files(['Tags', $tagids[0]]);
267 $this->assertEquals('Birdwatching', $data->rawname);
268 $this->assertEmpty($files);
269
270 $data = $writer->get_data(['Tags', $tagids[1]]);
271 $files = $writer->get_files(['Tags', $tagids[1]]);
272 $this->assertEquals('Computers', $data->rawname);
273 $this->assertEquals(['computer.jpg'], array_keys($files));
274 }
1d3d4c66
MG
275
276 /**
277 * Test that only users within a system context are fetched.
278 */
279 public function test_get_users_in_context() {
280 $component = 'core_tag';
281
282 $user1 = $this->set_up_tags()[0];
283 $systemcontext = context_system::instance();
284
285 $userlist1 = new \core_privacy\local\request\userlist($systemcontext, $component);
286 provider::get_users_in_context($userlist1);
287 $this->assertCount(1, $userlist1);
288 $expected = [$user1->id];
289 $actual = $userlist1->get_userids();
290 $this->assertEquals($expected, $actual);
291
292 // The list of users within the a context other than system context should be empty.
293 $usercontext1 = context_user::instance($user1->id);
294 $userlist2 = new \core_privacy\local\request\userlist($usercontext1, $component);
295 provider::get_users_in_context($userlist2);
296 $this->assertCount(0, $userlist2);
297 }
298
299 /**
300 * Test that data for users in approved userlist is deleted.
301 */
302 public function test_delete_data_for_users() {
303 $component = 'core_tag';
304
305 list($user1, $user2) = $this->set_up_tags();
306 $usercontext1 = context_user::instance($user1->id);
307 $user3 = $this->getDataGenerator()->create_user();
308 $systemcontext = context_system::instance();
309
310 $this->setUser($user2);
311 useredit_update_interests($user2, ['basketball']);
312
313 $this->setUser($user3);
314 useredit_update_interests($user3, ['soccer']);
315
316 $userlist = new \core_privacy\local\request\userlist($systemcontext, $component);
317 provider::get_users_in_context($userlist);
318 $this->assertCount(3, $userlist);
319 $this->assertTrue(in_array($user1->id, $userlist->get_userids()));
320 $this->assertTrue(in_array($user2->id, $userlist->get_userids()));
321 $this->assertTrue(in_array($user3->id, $userlist->get_userids()));
322
323 // Data should not be deleted in contexts other than system context.
324 // Convert $userlist into an approved_contextlist.
325 $approvedlist = new approved_userlist($usercontext1, $component, $userlist->get_userids());
326 // Delete using delete_data_for_user.
327 provider::delete_data_for_users($approvedlist);
328 // Re-fetch users in systemcontext.
329 $userlist = new \core_privacy\local\request\userlist($systemcontext, $component);
330 provider::get_users_in_context($userlist);
331 // The user data in systemcontext should not be deleted.
332 $this->assertCount(3, $userlist);
333
334 // Add user1 and user2 into an approved_contextlist.
335 $approvedlist = new approved_userlist($systemcontext, $component, [$user1->id, $user2->id]);
336 // Delete using delete_data_for_user.
337 provider::delete_data_for_users($approvedlist);
338 // Re-fetch users in systemcontext.
339 $userlist = new \core_privacy\local\request\userlist($systemcontext, $component);
340 provider::get_users_in_context($userlist);
341 // The approved user data in systemcontext should be deleted.
342 // The user list should return user3.
343 $this->assertCount(1, $userlist);
344 $this->assertTrue(in_array($user3->id, $userlist->get_userids()));
345 }
e4f6c0c2 346}