on-demand release 4.0dev+
[moodle.git] / contentbank / 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  * Base class for unit tests for core_contentbank.
19  *
20  * @package    core_contentbank
21  * @category   test
22  * @copyright  2020 Carlos Escobedo <carlos@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 namespace core_contentbank;
28 use stdClass;
29 use context_system;
30 use context_coursecat;
31 use context_course;
32 use context_user;
33 use core_contentbank\privacy\provider;
34 use core_privacy\local\request\approved_contextlist;
35 use core_privacy\local\request\writer;
36 use core_privacy\tests\provider_testcase;
37 use core_privacy\local\request\userlist;
38 use core_privacy\local\request\approved_userlist;
40 /**
41  * Unit tests for contentbank\classes\privacy\provider.php
42  *
43  * @copyright  2020 Carlos Escobedo <carlos@moodle.com>
44  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45  */
46 class core_contentbank_privacy_testcase extends provider_testcase {
48     /**
49      * Setup to ensure that fixtures are loaded.
50      */
51     public static function setupBeforeClass(): void {
52         global $CFG;
53         require_once($CFG->dirroot . '/contentbank/tests/fixtures/testable_content.php');
54     }
56     /**
57      * Test for provider::get_contexts_for_userid().
58      */
59     public function test_get_contexts_for_userid() {
61         $this->resetAfterTest();
62         // Setup scenario.
63         $scenario = $this->setup_scenario();
65         // Testing againts Manager who has content in the three contexts.
66         $contextlist = provider::get_contexts_for_userid($scenario->manager->id);
67         // There are three contexts in the list.
68         $contextlistids = $contextlist->get_contextids();
69         $this->assertCount(3, $contextlistids);
70         // Check the list against the expected list of contexts.
71         $this->assertContainsEquals($scenario->systemcontext->id, $contextlistids);
72         $this->assertContainsEquals($scenario->coursecategorycontext->id,
73             $contextlistids);
74         $this->assertContainsEquals($scenario->coursecontext->id, $contextlistids);
76         // Testing againts Teacher who has content in the one context.
77         $contextlist = provider::get_contexts_for_userid($scenario->teacher->id);
78         // There are only one context in the list.
79         $contextlistids = $contextlist->get_contextids();
80         $this->assertCount(1, $contextlistids);
81         // Check the againts Course Context.
82         $this->assertContainsEquals($scenario->coursecontext->id, $contextlistids);
83         // And there is not a System and Course Category Context.
84         $this->assertNotContainsEquals($scenario->systemcontext->id, $contextlistids);
85         $this->assertNotContainsEquals($scenario->coursecategorycontext->id, $contextlistids);
86     }
88     /**
89      * Test for provider::get_users_in_context().
90      */
91     public function test_get_users_in_context() {
93         $this->resetAfterTest();
94         // Setup scenario.
95         $scenario = $this->setup_scenario();
97         // Get the userlist to Context System, only Manager will be there.
98         $userlist = new userlist($scenario->systemcontext, 'core_contentbank');
99         provider::get_users_in_context($userlist);
100         $this->assertEquals([$scenario->manager->id], $userlist->get_userids());
101         // Teacher will not be there.
102         $this->assertNotEquals([$scenario->teacher->id], $userlist->get_userids());
104         // Get the userlist to Context Course, Manager and Teacher will be there.
105         $userlist = new userlist($scenario->coursecontext, 'core_contentbank');
106         provider::get_users_in_context($userlist);
108         $expected = [$scenario->manager->id, $scenario->teacher->id];
109         sort($expected);
110         $actual = $userlist->get_userids();
111         sort($actual);
112         $this->assertEquals($expected, $actual);
113     }
115     /**
116      * Test for provider::test_export_user_data().
117      */
118     public function test_export_user_data() {
120         $this->resetAfterTest();
121         // Setup scenario.
122         $scenario = $this->setup_scenario();
124         $subcontexts = [
125             get_string('name', 'core_contentbank')
126         ];
127         // Get the data for the System Context.
128         $writer = writer::with_context($scenario->systemcontext);
129         $this->assertFalse($writer->has_any_data());
130         // Export data for Manager.
131         $this->export_context_data_for_user($scenario->manager->id,
132             $scenario->systemcontext, 'core_contentbank');
133         $data = $writer->get_data($subcontexts);
134         $this->assertCount(3, (array) $data);
135         $this->assertCount(3, $writer->get_files($subcontexts));
137         // Get the data for the Course Categoy Context.
138         $writer = writer::with_context($scenario->coursecategorycontext);
139         // Export data for Manager.
140         $this->export_context_data_for_user($scenario->manager->id,
141             $scenario->coursecategorycontext, 'core_contentbank');
142         $data = $writer->get_data($subcontexts);
143         $this->assertCount(2, (array) $data);
144         $this->assertCount(2, $writer->get_files($subcontexts));
146         // Get the data for the Course Context.
147         $writer = writer::with_context($scenario->coursecontext);
148         // Export data for Manager.
149         $this->export_context_data_for_user($scenario->manager->id,
150             $scenario->coursecontext, 'core_contentbank');
151         $data = $writer->get_data($subcontexts);
152         $this->assertCount(2, (array) $data);
153         $this->assertCount(2, $writer->get_files($subcontexts));
155         // Export data for Teacher.
156         $writer = writer::reset();
157         $writer = writer::with_context($scenario->coursecontext);
158         $this->export_context_data_for_user($scenario->teacher->id,
159             $scenario->coursecontext, 'core_contentbank');
160         $data = $writer->get_data($subcontexts);
161         $this->assertCount(3, (array) $data);
162         $this->assertCount(3, $writer->get_files($subcontexts));
163     }
165     /**
166      * Test for provider::delete_data_for_all_users_in_context().
167      */
168     public function test_delete_data_for_all_users_in_context() {
169         global $DB;
171         $this->resetAfterTest();
172         // Setup scenario.
173         $scenario = $this->setup_scenario();
175         // Before delete data, we have 4 contents.
176         // - 3 in a system context.
177         // - 2 in a course category context.
178         // - 5 in a course context (2 by manager and 3 by teacher).
180         // Delete data based on system context.
181         provider::delete_data_for_all_users_in_context($scenario->systemcontext);
182         $count = $DB->count_records('contentbank_content');
183         // 3 content should be deleted.
184         // 7 contents should be remain.
185         $this->assertEquals(7, $count);
187         // Delete data based on course category context.
188         provider::delete_data_for_all_users_in_context($scenario->coursecategorycontext);
189         $count = $DB->count_records('contentbank_content');
190         // 2 contents should be deleted.
191         // 5 content should be remain.
192         $this->assertEquals(5, $count);
194         // Delete data based on course context.
195         provider::delete_data_for_all_users_in_context($scenario->coursecontext);
196          $count = $DB->count_records('contentbank_content');
197         // 5 content should be deleted.
198         // 0 content should be remain.
199         $this->assertEquals(0, $count);
200     }
202     /**
203      * Test for provider::test_delete_data_for_users().
204      */
205     public function test_delete_data_for_users() {
206         global $DB;
208         $this->resetAfterTest();
209         // Setup scenario.
210         $scenario = $this->setup_scenario();
212         // Before delete data, we have 4 contents.
213         // - 3 in a system context.
214         // - 2 in a course category context.
215         // - 5 in a course context (2 by manager and 3 by teacher).
217         // A list of users who has created content in Course Category Context.
218         $userlist1 = new userlist($scenario->coursecategorycontext,
219             'core_contentbank');
220         provider::get_users_in_context($userlist1);
221         $this->assertCount(1, $userlist1);
222         // Only Manager should be.
223         $this->assertEquals([$scenario->manager->id], $userlist1->get_userids());
225         // A list of users who has created content in Course Context.
226         $userlist2 = new userlist($scenario->coursecontext, 'core_contentbank');
227         provider::get_users_in_context($userlist2);
228         $this->assertCount(2, $userlist2);
230         // Manager and Teacher should be.
231         $expected = [$scenario->manager->id, $scenario->teacher->id];
232         sort($expected);
233         $actual = $userlist2->get_userids();
234         sort($actual);
235         $this->assertEquals($expected, $actual);
237         // Convert $userlist1 into an approved_contextlist.
238         $approvedlist1 = new approved_userlist($scenario->coursecategorycontext, 'core_contentbank', $userlist1->get_userids());
239         // Delete data for users in course category context.
240         provider::delete_data_for_users($approvedlist1);
242         // Re-fetch users in course category context.
243         $userlist1 = new userlist($scenario->coursecategorycontext,
244             'core_contentbank');
245         provider::get_users_in_context($userlist1);
246         // The user data in course category context should be deleted.
247         $this->assertCount(0, $userlist1);
248         // Re-fetch users in course category context.
249         $userlist2 = new userlist($scenario->coursecontext, 'core_contentbank');
250         provider::get_users_in_context($userlist2);
251         // The user data in course context should be still present.
252         $this->assertCount(2, $userlist2);
254         // Convert $userlist2 into an approved_contextlist.
255         $approvedlist2 = new approved_userlist($scenario->coursecontext,
256             'core_contentbank', $userlist2->get_userids());
257         // Delete data for users in course context.
258         provider::delete_data_for_users($approvedlist2);
259         $userlist2 = new userlist($scenario->coursecontext, 'core_contentbank');
260         provider::get_users_in_context($userlist2);
261         // The user data in course context should be deleted.
262         $this->assertCount(0, $userlist2);
263     }
265     /**
266      * Test for provider::delete_data_for_user().
267      */
268     public function test_delete_data_for_user() {
269          global $DB;
271         $this->resetAfterTest();
272         // Setup scenario.
273         $scenario = $this->setup_scenario();
275         // Before delete data, we have 4 contents.
276         // - 3 in a system context.
277         // - 2 in a course category context.
278         // - 5 in a course context (2 by manager and 3 by teacher).
280         // Get all the context for Manager.
281         $contextlist = provider::get_contexts_for_userid($scenario->manager->id);
282         $approvedcontextlist = new approved_contextlist($scenario->manager,
283             'core_contentbank', $contextlist->get_contextids());
284         // Delete all the data created by the Manager in all the contexts.
285         provider::delete_data_for_user($approvedcontextlist);
287         // After deletion, only 3 content for teacher should be present.
288         $count = $DB->count_records('contentbank_content');
289         $this->assertEquals(3, $count);
291         // Confirm that the remaining content was created by the teacher.
292         $count = $DB->count_records('contentbank_content',
293             ['usercreated' => $scenario->teacher->id]);
294         $this->assertEquals(3, $count);
296         // Get all the context for Teacher.
297         $contextlist = provider::get_contexts_for_userid($scenario->teacher->id);
298         $approvedcontextlist = new approved_contextlist($scenario->teacher,
299             'core_contentbank', $contextlist->get_contextids());
300         // Delete all the data created by the Teacher in all the contexts.
301         provider::delete_data_for_user($approvedcontextlist);
303         // After deletion, no content should be present.
304         $count = $DB->count_records('contentbank_content');
305         $this->assertEquals(0, $count);
306     }
308     /**
309      * Create a complex scenario to use into the tests.
310      *
311      * @return stdClass $scenario
312      */
313     protected function setup_scenario() {
314         global $DB;
316         $systemcontext = context_system::instance();
317         $manager = $this->getDataGenerator()->create_user();
318         $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
319         $this->getDataGenerator()->role_assign($managerroleid, $manager->id);
321         $coursecategory = $this->getDataGenerator()->create_category();
322         $coursecategorycontext = context_coursecat::instance($coursecategory->id);
324         $course = $this->getDataGenerator()->create_course();
325         $coursecontext = context_course::instance($course->id);
326         $teacher = $this->getDataGenerator()->create_and_enrol($course,
327             'editingteacher');
329         // Add some content to the content bank.
330         $generator = $this->getDataGenerator()->get_plugin_generator('core_contentbank');
331         // Add contents by Manager in Context System.
332         $records = $generator->generate_contentbank_data('contenttype_testable',
333             1, $manager->id, $systemcontext, false, 'systemtestfile1.h5p');
334         $records = $generator->generate_contentbank_data('contenttype_testable',
335             1, $manager->id, $systemcontext, false, 'systemtestfile2.h5p');
336         $records = $generator->generate_contentbank_data('contenttype_testable',
337             1, $manager->id, $systemcontext, false, 'systemtestfile3.h5p');
338         // Add contents by Manager in Context Course Category.
339         $records = $generator->generate_contentbank_data('contenttype_testable',
340             1, $manager->id, $coursecategorycontext, false, 'coursecattestfile1.h5p');
341         $records = $generator->generate_contentbank_data('contenttype_testable',
342             1, $manager->id, $coursecategorycontext, false, 'coursecattestfile2.h5p');
343         // Add contents by Manager in Context Course.
344         $records = $generator->generate_contentbank_data('contenttype_testable',
345             1, $manager->id, $coursecontext, false, 'coursetestfile1.h5p');
346         $records = $generator->generate_contentbank_data('contenttype_testable',
347             1, $manager->id, $coursecontext, false, 'coursetestfile2.h5p');
348         // Add contents by Teacher.
349         $records = $generator->generate_contentbank_data('contenttype_testable',
350             1, $teacher->id, $coursecontext, false, 'courseteacherfile1.h5p');
351         $records = $generator->generate_contentbank_data('contenttype_testable',
352             1, $teacher->id, $coursecontext, false, 'courseteacherfile2.h5p');
353         $records = $generator->generate_contentbank_data('contenttype_testable',
354             1, $teacher->id, $coursecontext, false, 'courseteacherfile3.h5p');
356         $scenario = new stdClass();
357         $scenario->systemcontext = $systemcontext;
358         $scenario->coursecategorycontext = $coursecategorycontext;
359         $scenario->coursecontext = $coursecontext;
360         $scenario->manager = $manager;
361         $scenario->teacher = $teacher;
363         return $scenario;
364     }
366     /**
367      * Ensure that export_user_preferences returns no data if the user has not visited any content bank.
368      */
369     public function test_export_user_preferences_no_pref() {
370         global $DB;
372         $this->resetAfterTest();
373         $user = $this->getDataGenerator()->create_user();
374         $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
375         $this->getDataGenerator()->role_assign($managerroleid, $user->id);
377         provider::export_user_preferences($user->id);
378         $writer = writer::with_context(context_system::instance());
379         $this->assertFalse($writer->has_any_data());
380     }
382     /**
383      * Test for provider::test_export_user_preferences().
384      */
385     public function test_export_user_preferences() {
386         global $DB;
388         // Test setup.
389         $this->resetAfterTest(true);
390         $user = $this->getDataGenerator()->create_user();
391         $this->setUser($user);
393         set_user_preference('core_contentbank_view_list', 1);
394         // Test the user preferences export contains 1 user preference record for the User.
395         provider::export_user_preferences($user->id);
396         $contextuser = context_user::instance($user->id);
397         $writer = writer::with_context($contextuser);
398         $this->assertTrue($writer->has_any_data());
400         $prefs = $writer->get_user_preferences('core_contentbank');
401         $this->assertCount(1, (array) $prefs);
402         $this->assertEquals(1, $prefs->core_contentbank_view_list->value);
403         $this->assertEquals(
404                 get_string('privacy:request:preference:set', 'core_contentbank', (object) [
405                         'name' => 'core_contentbank_view_list',
406                         'value' => $prefs->core_contentbank_view_list->value,
407                 ]),
408                 $prefs->core_contentbank_view_list->description
409         );
410     }