MDL-63688 core_tag: Add method that returns users in context
[moodle.git] / tag / tests / privacy_test.php
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/>.
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  */
26 defined('MOODLE_INTERNAL') || die();
27 global $CFG;
29 require_once($CFG->dirroot . '/tag/lib.php');
31 use \core_privacy\tests\provider_testcase;
32 use \core_privacy\local\request\writer;
33 use \core_tag\privacy\provider;
34 use \core_privacy\local\request\approved_userlist;
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  */
42 class core_tag_privacy_testcase extends provider_testcase {
44     /**
45      * Check the exporting of tags for a user id in a context.
46      */
47     public function test_export_tags() {
48         global $DB;
50         $this->resetAfterTest(true);
52         // Create a user to perform tagging.
53         $user = $this->getDataGenerator()->create_user();
54         $this->setUser($user);
56         // Create a course to tag.
57         $course = $this->getDataGenerator()->create_course();
58         $context = context_course::instance($course->id);
59         $subcontext = [];
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);
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);
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         }
76         // Retrieve tags only for this user.
77         provider::export_item_tags($user->id, $context, $subcontext, 'core_course', 'course', $course->id, true);
79         $writer = writer::with_context($context);
80         $this->assertTrue($writer->has_any_data());
82         $exportedtags = $writer->get_related_data($subcontext, 'tags');
83         $this->assertCount(count($dummytags), $exportedtags);
85         // Check the exported tag's rawname is found in the initial dummy tags.
86         foreach ($exportedtags as $exportedtag) {
87             $this->assertContains($exportedtag, $dummytags);
88         }
89     }
91     /**
92      * Test method delete_item_tags().
93      */
94     public function test_delete_item_tags() {
95         global $DB;
97         $this->resetAfterTest(true);
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);
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']);
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'));
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'));
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     }
125     /**
126      * Test method delete_item_tags() with userid.
127      */
128     public function test_delete_item_tags_with_userid() {
129         global $DB;
131         $this->resetAfterTest(true);
132         // Create a course to tag.
133         $course = $this->getDataGenerator()->create_course();
134         $context = context_course::instance($course->id);
136         // Create a user to perform tagging.
137         $user = $this->getDataGenerator()->create_user();
138         $this->setUser($user);
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');
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'));
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     }
154     /**
155      * Test method delete_item_tags_select().
156      */
157     public function test_delete_item_tags_select() {
158         global $DB;
160         $this->resetAfterTest(true);
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);
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']);
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'));
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     }
185     protected function set_up_tags() {
186         global $CFG;
187         require_once($CFG->dirroot.'/user/editlib.php');
189         $this->resetAfterTest(true);
191         $user1 = $this->getDataGenerator()->create_user();
192         $user2 = $this->getDataGenerator()->create_user();
194         $this->setUser($user1);
195         useredit_update_interests($user1, ['Birdwatching', 'Computers']);
197         $this->setUser($user2);
198         useredit_update_interests($user2, ['computers']);
200         $this->setAdminUser();
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");
213         return [$user1, $user2];
214     }
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     }
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     }
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     }
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());
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'])));
262         provider::export_user_data(new \core_privacy\local\request\approved_contextlist($user1, 'core_tag', [$context->id]));
263         $writer = writer::with_context($context);
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);
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     }
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';
282         $user1 = $this->set_up_tags()[0];
283         $systemcontext = context_system::instance();
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);
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     }
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';
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();
310         $this->setUser($user2);
311         useredit_update_interests($user2, ['basketball']);
313         $this->setUser($user3);
314         useredit_update_interests($user3, ['soccer']);
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()));
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);
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     }