MDL-63711 core_grade: Use canonicalize for checking userlist IDs
[moodle.git] / grade / 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  * Data provider tests.
19  *
20  * @package    core_grades
21  * @category   test
22  * @copyright  2018 Frédéric Massart
23  * @author     Frédéric Massart <fred@branchup.tech>
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
30 use core_privacy\tests\provider_testcase;
31 use core_privacy\local\request\approved_contextlist;
32 use core_privacy\local\request\transform;
33 use core_privacy\local\request\writer;
34 use core_grades\privacy\provider;
36 require_once($CFG->libdir . '/gradelib.php');
38 /**
39  * Data provider testcase class.
40  *
41  * @package    core_grades
42  * @category   test
43  * @copyright  2018 Frédéric Massart
44  * @author     Frédéric Massart <fred@branchup.tech>
45  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46  */
47 class core_grades_privacy_testcase extends provider_testcase {
49     public function setUp() {
50         global $PAGE;
51         $this->resetAfterTest();
52         $PAGE->get_renderer('core');
53     }
55     public function test_get_contexts_for_userid_gradebook_edits() {
56         $dg = $this->getDataGenerator();
58         $c1 = $dg->create_course();
59         $c2 = $dg->create_course();
61         $u1 = $dg->create_user();
62         $u2 = $dg->create_user();
63         $u3 = $dg->create_user();
64         $u4 = $dg->create_user();
65         $u5 = $dg->create_user();
66         $u6 = $dg->create_user();
67         $u7 = $dg->create_user();
68         $u8 = $dg->create_user();
69         $u9 = $dg->create_user();
70         $u10 = $dg->create_user();
71         $u11 = $dg->create_user();
73         $sysctx = context_system::instance();
74         $c1ctx = context_course::instance($c1->id);
75         $c2ctx = context_course::instance($c2->id);
77         // Create some stuff.
78         $gi1a = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
79         $gi1b = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
80         $gi2a = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
81         $gc1a = new grade_category($dg->create_grade_category(['courseid' => $c1->id]), false);
82         $gc1b = new grade_category($dg->create_grade_category(['courseid' => $c1->id]), false);
83         $gc2a = new grade_category($dg->create_grade_category(['courseid' => $c2->id]), false);
84         $go2 = new grade_outcome($dg->create_grade_outcome(['courseid' => $c2->id, 'shortname' => 'go2',
85             'fullname' => 'go2']), false);
87         // Nothing as of now.
88         foreach ([$u1, $u2, $u3, $u4, $u5, $u6, $u7, $u8, $u9, $u10, $u11] as $u) {
89             $contexts = array_flip(provider::get_contexts_for_userid($u->id)->get_contextids());
90             $this->assertEmpty($contexts);
91         }
93         $go0 = new grade_outcome(['shortname' => 'go0', 'fullname' => 'go0', 'usermodified' => $u1->id]);
94         $go0->insert();
95         $go1 = new grade_outcome(['shortname' => 'go1', 'fullname' => 'go1', 'courseid' => $c1->id, 'usermodified' => $u11->id]);
96         $go1->insert();
98         // Create scales.
99         $s1 = new grade_scale(['name' => 's1', 'scale' => 'a,b', 'userid' => $u7->id, 'courseid' => 0, 'description' => '']);
100         $s1->insert();
101         $s2 = new grade_scale(['name' => 's2', 'scale' => 'a,b', 'userid' => $u8->id, 'courseid' => $c1->id, 'description' => '']);
102         $s2->insert();
104         // User 2 creates history.
105         $this->setUser($u2);
106         $go0->shortname .= ' edited';
107         $go0->update();
108         $gc1a->fullname .= ' edited';
109         $gc1a->update();
111         // User 3 creates history.
112         $this->setUser($u3);
113         $go1->shortname .= ' edited';
114         $go1->update();
115         $gc2a->fullname .= ' a';
116         $gc2a->update();
118         // User 4 updates an outcome in course (creates history).
119         $this->setUser($u4);
120         $go2->shortname .= ' edited';
121         $go2->update();
123         // User 5 updates an item.
124         $this->setUser($u5);
125         $gi1a->itemname .= ' edited';
126         $gi1a->update();
128         // User 6 creates history.
129         $this->setUser($u6);
130         $gi2a->delete();
132         // User 9 creates history.
133         $this->setUser($u9);
134         $s1->name .= ' edited';
135         $s1->update();
137         // Assert contexts.
138         $contexts = array_flip(provider::get_contexts_for_userid($u1->id)->get_contextids());
139         $this->assertCount(1, $contexts);
140         $this->assertArrayHasKey($sysctx->id, $contexts);
141         $contexts = array_flip(provider::get_contexts_for_userid($u11->id)->get_contextids());
142         $this->assertCount(1, $contexts);
143         $this->assertArrayHasKey($c1ctx->id, $contexts);
144         $contexts = array_flip(provider::get_contexts_for_userid($u2->id)->get_contextids());
145         $this->assertCount(2, $contexts);
146         $this->assertArrayHasKey($sysctx->id, $contexts);
147         $this->assertArrayHasKey($c1ctx->id, $contexts);
148         $contexts = array_flip(provider::get_contexts_for_userid($u3->id)->get_contextids());
149         $this->assertCount(2, $contexts);
150         $this->assertArrayHasKey($c1ctx->id, $contexts);
151         $this->assertArrayHasKey($c2ctx->id, $contexts);
152         $contexts = array_flip(provider::get_contexts_for_userid($u4->id)->get_contextids());
153         $this->assertCount(1, $contexts);
154         $this->assertArrayHasKey($c2ctx->id, $contexts);
155         $contexts = array_flip(provider::get_contexts_for_userid($u5->id)->get_contextids());
156         $this->assertCount(1, $contexts);
157         $this->assertArrayHasKey($c1ctx->id, $contexts);
158         $contexts = array_flip(provider::get_contexts_for_userid($u6->id)->get_contextids());
159         $this->assertCount(1, $contexts);
160         $this->assertArrayHasKey($c2ctx->id, $contexts);
161         $contexts = array_flip(provider::get_contexts_for_userid($u7->id)->get_contextids());
162         $this->assertCount(1, $contexts);
163         $this->assertArrayHasKey($sysctx->id, $contexts);
164         $contexts = array_flip(provider::get_contexts_for_userid($u8->id)->get_contextids());
165         $this->assertCount(1, $contexts);
166         $this->assertArrayHasKey($c1ctx->id, $contexts);
167         $contexts = array_flip(provider::get_contexts_for_userid($u9->id)->get_contextids());
168         $this->assertCount(1, $contexts);
169         $this->assertArrayHasKey($sysctx->id, $contexts);
171         // User 10 creates history.
172         $this->setUser($u10);
173         $s2->delete();
175         $contexts = array_flip(provider::get_contexts_for_userid($u10->id)->get_contextids());
176         $this->assertCount(1, $contexts);
177         $this->assertArrayHasKey($c1ctx->id, $contexts);
178     }
180     public function test_get_contexts_for_userid_grades_and_history() {
181         $dg = $this->getDataGenerator();
183         $c1 = $dg->create_course();
184         $c2 = $dg->create_course();
186         $u1 = $dg->create_user();
187         $u2 = $dg->create_user();
188         $u3 = $dg->create_user();
189         $u4 = $dg->create_user();
190         $u5 = $dg->create_user();
191         $u6 = $dg->create_user();
193         $sysctx = context_system::instance();
194         $c1ctx = context_course::instance($c1->id);
195         $c2ctx = context_course::instance($c2->id);
197         // Create some stuff.
198         $gi1a = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
199         $gi1b = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
200         $gi2a = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
201         $gi2b = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
203         // Nothing as of now.
204         foreach ([$u1, $u2, $u3, $u4, $u5, $u6] as $u) {
205             $contexts = array_flip(provider::get_contexts_for_userid($u->id)->get_contextids());
206             $this->assertEmpty($contexts);
207         }
209         // User 1 is graded in course 1.
210         $gi1a->update_final_grade($u1->id, 1, 'test');
212         // User 2 is graded in course 2.
213         $gi2a->update_final_grade($u2->id, 10, 'test');
215         // User 3 is set as modifier.
216         $gi1a->update_final_grade($u1->id, 1, 'test', '', FORMAT_MOODLE, $u3->id);
218         // User 4 is set as modifier, and creates history..
219         $this->setUser($u4);
220         $gi1a->update_final_grade($u2->id, 1, 'test');
222         // User 5 creates history, user 6 is the known modifier, and we delete the item.
223         $this->setUser($u5);
224         $gi2b->update_final_grade($u2->id, 1, 'test', '', FORMAT_PLAIN, $u6->id);
225         $gi2b->delete();
227         // Assert contexts.
228         $contexts = array_flip(provider::get_contexts_for_userid($u1->id)->get_contextids());
229         $this->assertCount(1, $contexts);
230         $this->assertArrayHasKey($c1ctx->id, $contexts);
231         $contexts = array_flip(provider::get_contexts_for_userid($u2->id)->get_contextids());
232         $this->assertCount(3, $contexts);
233         $this->assertArrayHasKey($c1ctx->id, $contexts);
234         $this->assertArrayHasKey($c2ctx->id, $contexts);
235         $this->assertArrayHasKey(context_user::instance($u2->id)->id, $contexts);
236         $contexts = array_flip(provider::get_contexts_for_userid($u3->id)->get_contextids());
237         $this->assertCount(1, $contexts);
238         $this->assertArrayHasKey($c1ctx->id, $contexts);
239         $contexts = array_flip(provider::get_contexts_for_userid($u4->id)->get_contextids());
240         $this->assertCount(1, $contexts);
241         $this->assertArrayHasKey($c1ctx->id, $contexts);
242         $contexts = array_flip(provider::get_contexts_for_userid($u5->id)->get_contextids());
243         $this->assertCount(2, $contexts);
244         $this->assertArrayHasKey($c2ctx->id, $contexts);
245         $this->assertArrayHasKey(context_user::instance($u2->id)->id, $contexts);
246         $contexts = array_flip(provider::get_contexts_for_userid($u6->id)->get_contextids());
247         $this->assertCount(1, $contexts);
248         $this->assertArrayHasKey(context_user::instance($u2->id)->id, $contexts);
249     }
251     /**
252      * Test that the appropriate user IDs are returned for a given context.
253      */
254     public function test_get_users_in_context_gradebook_edits() {
255         $dg = $this->getDataGenerator();
257         $c1 = $dg->create_course();
258         $c2 = $dg->create_course();
260         $u1 = $dg->create_user();
261         $u2 = $dg->create_user();
262         $u3 = $dg->create_user();
263         $u4 = $dg->create_user();
264         $u5 = $dg->create_user();
265         $u6 = $dg->create_user();
266         $u7 = $dg->create_user();
267         $u8 = $dg->create_user();
268         $u9 = $dg->create_user();
269         $u10 = $dg->create_user();
270         $u11 = $dg->create_user();
272         $sysctx = context_system::instance();
273         $c1ctx = context_course::instance($c1->id);
274         $c2ctx = context_course::instance($c2->id);
276         // Create some stuff.
277         $gi1a = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
278         $gi1b = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
279         $gi2a = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
280         $gc1a = new grade_category($dg->create_grade_category(['courseid' => $c1->id]), false);
281         $gc1b = new grade_category($dg->create_grade_category(['courseid' => $c1->id]), false);
282         $gc2a = new grade_category($dg->create_grade_category(['courseid' => $c2->id]), false);
283         $go2 = new grade_outcome($dg->create_grade_outcome(['courseid' => $c2->id, 'shortname' => 'go2',
284             'fullname' => 'go2']), false);
286         $go0 = new grade_outcome(['shortname' => 'go0', 'fullname' => 'go0', 'usermodified' => $u1->id]);
287         $go0->insert();
288         $go1 = new grade_outcome(['shortname' => 'go1', 'fullname' => 'go1', 'courseid' => $c1->id, 'usermodified' => $u11->id]);
289         $go1->insert();
291         // Create scales.
292         $s1 = new grade_scale(['name' => 's1', 'scale' => 'a,b', 'userid' => $u7->id, 'courseid' => 0, 'description' => '']);
293         $s1->insert();
294         $s2 = new grade_scale(['name' => 's2', 'scale' => 'a,b', 'userid' => $u8->id, 'courseid' => $c1->id, 'description' => '']);
295         $s2->insert();
297         // User 2 creates history.
298         $this->setUser($u2);
299         $go0->shortname .= ' edited';
300         $go0->update();
301         $gc1a->fullname .= ' edited';
302         $gc1a->update();
304         // User 3 creates history.
305         $this->setUser($u3);
306         $go1->shortname .= ' edited';
307         $go1->update();
308         $gc2a->fullname .= ' a';
309         $gc2a->update();
311         // User 4 updates an outcome in course (creates history).
312         $this->setUser($u4);
313         $go2->shortname .= ' edited';
314         $go2->update();
316         // User 5 updates an item.
317         $this->setUser($u5);
318         $gi1a->itemname .= ' edited';
319         $gi1a->update();
321         // User 6 creates history.
322         $this->setUser($u6);
323         $gi2a->delete();
325         // User 9 creates history.
326         $this->setUser($u9);
327         $s1->name .= ' edited';
328         $s1->update();
330         $userlist = new \core_privacy\local\request\userlist($sysctx, 'core_grades');
331         provider::get_users_in_context($userlist);
332         $systemcontextuserids = [$u1->id, $u2->id, $u7->id, $u9->id];
333         $this->assertEquals($systemcontextuserids, $userlist->get_userids());
335         $userlist = new \core_privacy\local\request\userlist($c1ctx, 'core_grades');
336         provider::get_users_in_context($userlist);
337         $course1userids = [$u11->id, $u3->id, $u8->id, $u5->id, $u2->id];
338         $this->assertEquals($course1userids, $userlist->get_userids());
340         $userlist = new \core_privacy\local\request\userlist($c2ctx, 'core_grades');
341         provider::get_users_in_context($userlist);
342         $course2userids = [$u4->id, $u6->id, $u3->id];
343         $this->assertEquals($course2userids, $userlist->get_userids());
344     }
346     /**
347      * Test that the appropriate user IDs are returned for a given context.
348      */
349     public function test_get_users_in_context_grades_and_history() {
350         $dg = $this->getDataGenerator();
352         $c1 = $dg->create_course();
353         $c2 = $dg->create_course();
355         $u1 = $dg->create_user();
356         $u2 = $dg->create_user();
357         $u3 = $dg->create_user();
358         $u4 = $dg->create_user();
359         $u5 = $dg->create_user();
360         $u6 = $dg->create_user();
362         $c1ctx = context_course::instance($c1->id);
363         $c2ctx = context_course::instance($c2->id);
364         $u2ctx = context_user::instance($u2->id);
366         // Create some stuff.
367         $gi1a = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
368         $gi1b = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
369         $gi2a = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
370         $gi2b = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
372         // User 1 is graded in course 1.
373         $gi1a->update_final_grade($u1->id, 1, 'test');
375         // User 2 is graded in course 2.
376         $gi2a->update_final_grade($u2->id, 10, 'test');
378         // User 3 is set as modifier.
379         $gi1a->update_final_grade($u1->id, 1, 'test', '', FORMAT_MOODLE, $u3->id);
381         // User 4 is set as modifier, and creates history..
382         $this->setUser($u4);
383         $gi1a->update_final_grade($u2->id, 1, 'test');
385         // User 5 creates history, user 6 is the known modifier, and we delete the item.
386         $this->setUser($u5);
387         $gi2b->update_final_grade($u2->id, 1, 'test', '', FORMAT_PLAIN, $u6->id);
388         $gi2b->delete();
390         $userlist = new \core_privacy\local\request\userlist($c1ctx, 'core_grades');
391         provider::get_users_in_context($userlist);
392         $course1userids = [$u1->id, $u2->id, $u3->id, $u4->id];
393         $this->assertEquals($course1userids, $userlist->get_userids(), '', 0.0, 10, true);
395         $userlist = new \core_privacy\local\request\userlist($c2ctx, 'core_grades');
396         provider::get_users_in_context($userlist);
397         $course2userids = [$u5->id, $u2->id];
398         $this->assertEquals($course2userids, $userlist->get_userids(), '', 0.0, 10, true);
400         $userlist = new \core_privacy\local\request\userlist($u2ctx, 'core_grades');
401         provider::get_users_in_context($userlist);
402         $this->assertEquals([$u2->id], $userlist->get_userids());
403     }
405     public function test_delete_data_for_all_users_in_context() {
406         global $DB;
407         $dg = $this->getDataGenerator();
409         $c1 = $dg->create_course();
410         $c2 = $dg->create_course();
411         $u1 = $dg->create_user();
412         $u2 = $dg->create_user();
413         $u1ctx = context_user::instance($u1->id);
414         $c1ctx = context_course::instance($c1->id);
415         $c2ctx = context_course::instance($c2->id);
417         // Create some stuff.
418         $gi1a = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
419         $gi1b = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
420         $gi2a = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
421         $gi2b = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
423         $gi1a->update_final_grade($u1->id, 1, 'test');
424         $gi1a->update_final_grade($u2->id, 1, 'test');
425         $gi1b->update_final_grade($u1->id, 1, 'test');
426         $gi2a->update_final_grade($u1->id, 1, 'test');
427         $gi2a->update_final_grade($u2->id, 1, 'test');
428         $gi2b->update_final_grade($u1->id, 1, 'test');
429         $gi2b->update_final_grade($u2->id, 1, 'test');
430         $gi2b->delete();
432         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1a->id]));
433         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi1a->id]));
434         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1b->id]));
435         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
436         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
437         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u1->id, 'itemid' => $gi2b->id]));
438         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u2->id, 'itemid' => $gi2b->id]));
440         provider::delete_data_for_all_users_in_context($c1ctx);
441         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1a->id]));
442         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi1a->id]));
443         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1b->id]));
444         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
445         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
446         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u1->id, 'itemid' => $gi2b->id]));
447         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u2->id, 'itemid' => $gi2b->id]));
449         provider::delete_data_for_all_users_in_context($u1ctx);
450         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
451         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
452         $this->assertFalse($DB->record_exists('grade_grades_history', ['userid' => $u1->id, 'itemid' => $gi2b->id]));
453         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u2->id, 'itemid' => $gi2b->id]));
455         provider::delete_data_for_all_users_in_context($c2ctx);
456         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
457         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
458         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u2->id, 'itemid' => $gi2b->id]));
459     }
461     public function test_delete_data_for_user() {
462         global $DB;
463         $dg = $this->getDataGenerator();
465         $c1 = $dg->create_course();
466         $c2 = $dg->create_course();
467         $u1 = $dg->create_user();
468         $u2 = $dg->create_user();
469         $u1ctx = context_user::instance($u1->id);
470         $u2ctx = context_user::instance($u2->id);
471         $c1ctx = context_course::instance($c1->id);
472         $c2ctx = context_course::instance($c2->id);
474         // Create some stuff.
475         $gi1a = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
476         $gi1b = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
477         $gi2a = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
478         $gi2b = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
480         $gi1a->update_final_grade($u1->id, 1, 'test');
481         $gi1a->update_final_grade($u2->id, 1, 'test');
482         $gi1b->update_final_grade($u1->id, 1, 'test');
483         $gi2a->update_final_grade($u1->id, 1, 'test');
484         $gi2a->update_final_grade($u2->id, 1, 'test');
485         $gi2b->update_final_grade($u1->id, 1, 'test');
486         $gi2b->update_final_grade($u2->id, 1, 'test');
487         $gi2b->delete();
489         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1a->id]));
490         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi1a->id]));
491         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1b->id]));
492         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
493         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
494         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u1->id, 'itemid' => $gi2b->id]));
495         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u2->id, 'itemid' => $gi2b->id]));
497         provider::delete_data_for_user(new approved_contextlist($u1, 'core_grades', [$c1ctx->id]));
498         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1a->id]));
499         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi1a->id]));
500         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1b->id]));
501         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
502         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
503         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u1->id, 'itemid' => $gi2b->id]));
504         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u2->id, 'itemid' => $gi2b->id]));
506         provider::delete_data_for_user(new approved_contextlist($u1, 'core_grades', [$u1ctx->id]));
507         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1a->id]));
508         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi1a->id]));
509         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1b->id]));
510         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
511         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
512         $this->assertFalse($DB->record_exists('grade_grades_history', ['userid' => $u1->id, 'itemid' => $gi2b->id]));
513         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u2->id, 'itemid' => $gi2b->id]));
515         provider::delete_data_for_user(new approved_contextlist($u1, 'core_grades', [$u2ctx->id, $c2ctx->id]));
516         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1a->id]));
517         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi1a->id]));
518         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1b->id]));
519         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
520         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
521         $this->assertFalse($DB->record_exists('grade_grades_history', ['userid' => $u1->id, 'itemid' => $gi2b->id]));
522         $this->assertTrue($DB->record_exists('grade_grades_history', ['userid' => $u2->id, 'itemid' => $gi2b->id]));
523     }
525     /**
526      * Test deleting multiple users for a context works.
527      */
528     public function test_delete_data_for_users() {
529         global $DB;
530         $dg = $this->getDataGenerator();
532         $c1 = $dg->create_course();
533         $c2 = $dg->create_course();
534         $u1 = $dg->create_user();
535         $u2 = $dg->create_user();
536         $u3 = $dg->create_user();
537         $u4 = $dg->create_user();
538         $u1ctx = context_user::instance($u1->id);
539         $u2ctx = context_user::instance($u2->id);
540         $c1ctx = context_course::instance($c1->id);
541         $c2ctx = context_course::instance($c2->id);
543         // Create some stuff.
544         $gi1a = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
545         $gi1b = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
546         $gi2a = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
547         $gi2b = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
549         $gi1a->update_final_grade($u1->id, 1, 'test');
550         $gi1a->update_final_grade($u2->id, 1, 'test');
551         $gi1a->update_final_grade($u3->id, 1, 'test');
552         $gi1b->update_final_grade($u1->id, 1, 'test');
553         $gi1b->update_final_grade($u4->id, 1, 'test');
554         $gi2a->update_final_grade($u1->id, 1, 'test');
555         $gi2a->update_final_grade($u2->id, 1, 'test');
556         $gi2a->update_final_grade($u4->id, 1, 'test');
557         $gi2b->update_final_grade($u1->id, 1, 'test');
558         $gi2b->update_final_grade($u2->id, 1, 'test');
559         $gi2b->update_final_grade($u3->id, 1, 'test');
560         $gi2b->delete();
562         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1a->id]));
563         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi1a->id]));
564         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u3->id, 'itemid' => $gi1a->id]));
565         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1b->id]));
566         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u4->id, 'itemid' => $gi1b->id]));
567         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
568         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
569         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u4->id, 'itemid' => $gi2a->id]));
570         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2b->id]));
571         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2b->id]));
572         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u3->id, 'itemid' => $gi2b->id]));
574         $userlist = new \core_privacy\local\request\approved_userlist($c1ctx, 'core_grades', [$u1->id, $u2->id]);
575         provider::delete_data_for_users($userlist);
577         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1a->id]));
578         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi1a->id]));
579         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u3->id, 'itemid' => $gi1a->id]));
580         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1b->id]));
581         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u4->id, 'itemid' => $gi1b->id]));
582         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
583         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
584         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u4->id, 'itemid' => $gi2a->id]));
586         $userlist = new \core_privacy\local\request\approved_userlist($c2ctx, 'core_grades', [$u2->id, $u4->id]);
587         provider::delete_data_for_users($userlist);
589         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1a->id]));
590         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi1a->id]));
591         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u3->id, 'itemid' => $gi1a->id]));
592         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi1b->id]));
593         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u4->id, 'itemid' => $gi1b->id]));
594         $this->assertTrue($DB->record_exists('grade_grades', ['userid' => $u1->id, 'itemid' => $gi2a->id]));
595         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u2->id, 'itemid' => $gi2a->id]));
596         $this->assertFalse($DB->record_exists('grade_grades', ['userid' => $u4->id, 'itemid' => $gi2a->id]));
597     }
599     public function test_export_data_for_user_about_grades_and_history() {
600         global $DB;
601         $dg = $this->getDataGenerator();
603         $c1 = $dg->create_course();
604         $c2 = $dg->create_course();
606         // Users being graded.
607         $ug1 = $dg->create_user();
608         $ug2 = $dg->create_user();
609         $ug3 = $dg->create_user();
610         // Users performing actions.
611         $ua1 = $dg->create_user();
612         $ua2 = $dg->create_user();
613         $ua3 = $dg->create_user();
615         $ug1ctx = context_user::instance($ug1->id);
616         $ug2ctx = context_user::instance($ug2->id);
617         $c1ctx = context_course::instance($c1->id);
618         $c2ctx = context_course::instance($c2->id);
620         $rootpath = [get_string('grades', 'core_grades')];
621         $relatedtomepath = array_merge($rootpath, [get_string('privacy:path:relatedtome', 'core_grades')]);
623         // Create the course minimal stuff.
624         grade_category::fetch_course_category($c1->id);
625         $ci1 = grade_item::fetch_course_item($c1->id);
626         grade_category::fetch_course_category($c2->id);
627         $ci2 = grade_item::fetch_course_item($c2->id);
629         // Create data that will sit in the user context because we will delete the grate item.
630         $gi1 = new grade_item($dg->create_grade_item(['courseid' => $c1->id, 'aggregationcoef2' => 1]), false);
631         $gi1->update_final_grade($ug1->id, 100, 'test', 'Well done!', FORMAT_PLAIN, $ua2->id);
632         $gi1->update_final_grade($ug1->id, 1, 'test', 'Hi', FORMAT_PLAIN, $ua2->id);
633         $gi1->update_final_grade($ug3->id, 12, 'test', 'Hello', FORMAT_PLAIN, $ua2->id);
635         // Create another set for another user.
636         $gi2a = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
637         $gi2a->update_final_grade($ug1->id, 15, 'test', '', FORMAT_PLAIN, $ua2->id);
638         $gi2b = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
639         $gi2b->update_final_grade($ug1->id, 30, 'test', 'Well played!', FORMAT_PLAIN, $ua2->id);
641         // Export action user 1 everywhere.
642         provider::export_user_data(new approved_contextlist($ua1, 'core_grades', [$ug1ctx->id, $ug2ctx->id,
643             $c1ctx->id, $c2ctx->id]));
644         $this->assert_context_has_no_data($ug1ctx);
645         $this->assert_context_has_no_data($ug2ctx);
646         $this->assert_context_has_no_data($c1ctx);
647         $this->assert_context_has_no_data($c2ctx);
649         // Export action user 2 in course 1.
650         writer::reset();
651         provider::export_user_data(new approved_contextlist($ua2, 'core_grades', [$c1ctx->id]));
652         $this->assert_context_has_no_data($ug1ctx);
653         $this->assert_context_has_no_data($ug2ctx);
654         $this->assert_context_has_no_data($c2ctx);
655         $data = writer::with_context($c1ctx)->get_data($rootpath);
656         $this->assertEmpty($data);
658         // Here we are testing the export of grades that we've changed.
659         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'grades');
660         $this->assertCount(2, $data->grades);
661         $this->assertEquals($gi1->get_name(), $data->grades[0]['item']);
662         $this->assertEquals(1, $data->grades[0]['grade']);
663         $this->assertEquals('Hi', $data->grades[0]['feedback']);
664         $this->assertEquals(transform::yesno(true), $data->grades[0]['created_or_modified_by_you']);
665         $this->assertEquals($gi1->get_name(), $data->grades[1]['item']);
666         $this->assertEquals(12, $data->grades[1]['grade']);
667         $this->assertEquals('Hello', $data->grades[1]['feedback']);
668         $this->assertEquals(transform::yesno(true), $data->grades[1]['created_or_modified_by_you']);
670         // Here we are testing the export of history of grades that we've changed.
671         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'grades_history');
672         $this->assertCount(3, $data->modified_records);
673         $grade = $data->modified_records[0];
674         $this->assertEquals($ug1->id, $grade['userid']);
675         $this->assertEquals($gi1->get_name(), $grade['item']);
676         $this->assertEquals(100, $grade['grade']);
677         $this->assertEquals('Well done!', $grade['feedback']);
678         $this->assertEquals(transform::yesno(false), $grade['logged_in_user_was_you']);
679         $this->assertEquals(transform::yesno(true), $grade['author_of_change_was_you']);
680         $grade = $data->modified_records[1];
681         $this->assertEquals($ug1->id, $grade['userid']);
682         $this->assertEquals($gi1->get_name(), $grade['item']);
683         $this->assertEquals(1, $grade['grade']);
684         $this->assertEquals('Hi', $grade['feedback']);
685         $this->assertEquals(transform::yesno(false), $grade['logged_in_user_was_you']);
686         $this->assertEquals(transform::yesno(true), $grade['author_of_change_was_you']);
687         $grade = $data->modified_records[2];
688         $this->assertEquals($ug3->id, $grade['userid']);
689         $this->assertEquals($gi1->get_name(), $grade['item']);
690         $this->assertEquals(12, $grade['grade']);
691         $this->assertEquals('Hello', $grade['feedback']);
692         $this->assertEquals(transform::yesno(false), $grade['logged_in_user_was_you']);
693         $this->assertEquals(transform::yesno(true), $grade['author_of_change_was_you']);
695         // Create a history record with logged user.
696         $this->setUser($ua3);
697         $gi1->update_final_grade($ug3->id, 50, 'test', '...', FORMAT_PLAIN, $ua2->id);
698         writer::reset();
699         provider::export_user_data(new approved_contextlist($ua3, 'core_grades', [$c1ctx->id]));
700         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'grades_history');
701         $this->assertCount(1, $data->modified_records);
702         $grade = $data->modified_records[0];
703         $this->assertEquals($ug3->id, $grade['userid']);
704         $this->assertEquals($gi1->get_name(), $grade['item']);
705         $this->assertEquals(50, $grade['grade']);
706         $this->assertEquals('...', $grade['feedback']);
707         $this->assertEquals(transform::yesno(true), $grade['logged_in_user_was_you']);
708         $this->assertEquals(transform::yesno(false), $grade['author_of_change_was_you']);
710         // Test that we export our own grades.
711         writer::reset();
712         provider::export_user_data(new approved_contextlist($ug1, 'core_grades', [$c1ctx->id]));
713         $data = writer::with_context($c1ctx)->get_data($rootpath);
714         $this->assert_context_has_no_data($c2ctx);
715         $this->assertCount(2, $data->grades);
716         $grade = $data->grades[0];
717         $this->assertEquals($ci1->get_name(), $grade['item']);
718         $this->assertEquals(1, $grade['grade']);
719         $grade = $data->grades[1];
720         $this->assertEquals($gi1->get_name(), $grade['item']);
721         $this->assertEquals(1, $grade['grade']);
722         $this->assertEquals('Hi', $grade['feedback']);
724         // Test that we export our own grades in two courses.
725         writer::reset();
726         provider::export_user_data(new approved_contextlist($ug1, 'core_grades', [$ug1ctx->id, $c1ctx->id, $c2ctx->id]));
727         $this->assert_context_has_no_data($ug1ctx);
728         $data = writer::with_context($c1ctx)->get_data($rootpath);
729         $this->assertCount(2, $data->grades);
730         $grade = $data->grades[0];
731         $this->assertEquals($ci1->get_name(), $grade['item']);
732         $this->assertEquals(1, $grade['grade']);
733         $grade = $data->grades[1];
734         $this->assertEquals($gi1->get_name(), $grade['item']);
735         $this->assertEquals(1, $grade['grade']);
736         $this->assertEquals('Hi', $grade['feedback']);
738         $data = writer::with_context($c2ctx)->get_data($rootpath);
739         $this->assertCount(3, $data->grades);
740         $grade = $data->grades[0];
741         $this->assertEquals($ci2->get_name(), $grade['item']);
742         $grade = $data->grades[1];
743         $this->assertEquals($gi2a->get_name(), $grade['item']);
744         $this->assertEquals(15, $grade['grade']);
745         $this->assertEquals('', $grade['feedback']);
746         $grade = $data->grades[2];
747         $this->assertEquals($gi2b->get_name(), $grade['item']);
748         $this->assertEquals(30, $grade['grade']);
749         $this->assertEquals('Well played!', $grade['feedback']);
751         // Delete a grade item.
752         $this->setUser($ua3);
753         $gi1->delete();
755         // Now, we should find history of grades in our own context.
756         writer::reset();
757         provider::export_user_data(new approved_contextlist($ug1, 'core_grades', [$ug1ctx->id, $c1ctx->id, $c2ctx->id]));
758         $data = writer::with_context($c1ctx)->get_data($rootpath);
759         $this->assertCount(1, $data->grades);
760         $this->assertEquals($ci1->get_name(), $data->grades[0]['item']);
761         $data = writer::with_context($c2ctx)->get_data($rootpath);
762         $this->assertCount(3, $data->grades);
763         $data = writer::with_context($ug1ctx)->get_related_data($rootpath, 'history');
764         $this->assertCount(3, $data->grades);
765         $grade = $data->grades[0];
766         $this->assertEquals(get_string('privacy:request:unknowndeletedgradeitem', 'core_grades'), $grade['name']);
767         $this->assertEquals(100, $grade['grade']);
768         $this->assertEquals('Well done!', $grade['feedback']);
769         $this->assertEquals(transform::yesno(true), $grade['graded_user_was_you']);
770         $this->assertEquals(transform::yesno(false), $grade['logged_in_user_was_you']);
771         $this->assertEquals(transform::yesno(false), $grade['author_of_change_was_you']);
772         $this->assertEquals(get_string('privacy:request:historyactioninsert', 'core_grades'), $grade['action']);
773         $grade = $data->grades[1];
774         $this->assertEquals(get_string('privacy:request:unknowndeletedgradeitem', 'core_grades'), $grade['name']);
775         $this->assertEquals(1, $grade['grade']);
776         $this->assertEquals('Hi', $grade['feedback']);
777         $this->assertEquals(transform::yesno(true), $grade['graded_user_was_you']);
778         $this->assertEquals(transform::yesno(false), $grade['logged_in_user_was_you']);
779         $this->assertEquals(transform::yesno(false), $grade['author_of_change_was_you']);
780         $this->assertEquals(get_string('privacy:request:historyactionupdate', 'core_grades'), $grade['action']);
781         $grade = $data->grades[2];
782         $this->assertEquals(get_string('privacy:request:unknowndeletedgradeitem', 'core_grades'), $grade['name']);
783         $this->assertEquals(1, $grade['grade']);
784         $this->assertEquals('Hi', $grade['feedback']);
785         $this->assertEquals(transform::yesno(true), $grade['graded_user_was_you']);
786         $this->assertEquals(transform::yesno(false), $grade['logged_in_user_was_you']);
787         $this->assertEquals(transform::yesno(false), $grade['author_of_change_was_you']);
788         $this->assertEquals(get_string('privacy:request:historyactiondelete', 'core_grades'), $grade['action']);
790         // The action user 3 should have a record of the deletion in the user's context.
791         writer::reset();
792         provider::export_user_data(new approved_contextlist($ua3, 'core_grades', [$ug1ctx->id]));
793         $data = writer::with_context($ug1ctx)->get_related_data($rootpath, 'history');
794         $this->assertCount(1, $data->grades);
795         $grade = $data->grades[0];
796         $this->assertEquals(get_string('privacy:request:unknowndeletedgradeitem', 'core_grades'), $grade['name']);
797         $this->assertEquals(1, $grade['grade']);
798         $this->assertEquals('Hi', $grade['feedback']);
799         $this->assertEquals(transform::yesno(true), $grade['logged_in_user_was_you']);
800         $this->assertEquals(transform::yesno(false), $grade['author_of_change_was_you']);
801         $this->assertEquals(get_string('privacy:request:historyactiondelete', 'core_grades'), $grade['action']);
803         // The action user 2 should have a record of their edits in the user's context.
804         writer::reset();
805         provider::export_user_data(new approved_contextlist($ua2, 'core_grades', [$ug1ctx->id]));
806         $data = writer::with_context($ug1ctx)->get_related_data($rootpath, 'history');
807         $this->assertCount(3, $data->grades);
808         $grade = $data->grades[0];
809         $this->assertEquals(get_string('privacy:request:unknowndeletedgradeitem', 'core_grades'), $grade['name']);
810         $this->assertEquals(100, $grade['grade']);
811         $this->assertEquals('Well done!', $grade['feedback']);
812         $this->assertEquals(transform::yesno(false), $grade['logged_in_user_was_you']);
813         $this->assertEquals(transform::yesno(true), $grade['author_of_change_was_you']);
814         $this->assertEquals(get_string('privacy:request:historyactioninsert', 'core_grades'), $grade['action']);
815         $grade = $data->grades[1];
816         $this->assertEquals(get_string('privacy:request:unknowndeletedgradeitem', 'core_grades'), $grade['name']);
817         $this->assertEquals(1, $grade['grade']);
818         $this->assertEquals('Hi', $grade['feedback']);
819         $this->assertEquals(transform::yesno(false), $grade['logged_in_user_was_you']);
820         $this->assertEquals(transform::yesno(true), $grade['author_of_change_was_you']);
821         $this->assertEquals(get_string('privacy:request:historyactionupdate', 'core_grades'), $grade['action']);
822         $grade = $data->grades[2];
823         $this->assertEquals(get_string('privacy:request:unknowndeletedgradeitem', 'core_grades'), $grade['name']);
824         $this->assertEquals(1, $grade['grade']);
825         $this->assertEquals('Hi', $grade['feedback']);
826         $this->assertEquals(transform::yesno(false), $grade['logged_in_user_was_you']);
827         $this->assertEquals(transform::yesno(true), $grade['author_of_change_was_you']);
828         $this->assertEquals(get_string('privacy:request:historyactiondelete', 'core_grades'), $grade['action']);
829     }
831     public function test_export_data_for_user_with_scale() {
832         global $DB;
833         $dg = $this->getDataGenerator();
834         $c1 = $dg->create_course();
835         $scale = $dg->create_scale(['scale' => 'Awesome,OK,Reasonable,Bad']);
836         $u1 = $dg->create_user();
837         $u2 = $dg->create_user();
839         $u1ctx = context_user::instance($u1->id);
840         $c1ctx = context_course::instance($c1->id);
842         $rootpath = [get_string('grades', 'core_grades')];
844         // Create another set for another user.
845         $gi1 = new grade_item($dg->create_grade_item(['courseid' => $c1->id, 'scaleid' => $scale->id]), false);
846         $gi1->update_final_grade($u1->id, 1, 'test', '', FORMAT_PLAIN, $u2->id);
847         $gi2 = new grade_item($dg->create_grade_item(['courseid' => $c1->id, 'scaleid' => $scale->id]), false);
848         $gi2->update_final_grade($u1->id, 3, 'test', '', FORMAT_PLAIN, $u2->id);
850         // Export user's data.
851         writer::reset();
852         provider::export_user_data(new approved_contextlist($u1, 'core_grades', [$c1ctx->id]));
853         $data = writer::with_context($c1ctx)->get_data($rootpath);
854         $this->assertCount(3, $data->grades);
855         $this->assertEquals(grade_item::fetch_course_item($c1->id)->get_name(), $data->grades[0]['item']);
856         $this->assertEquals($gi1->get_name(), $data->grades[1]['item']);
857         $this->assertEquals(1, $data->grades[1]['grade']);
858         $this->assertEquals('Awesome', $data->grades[1]['grade_formatted']);
859         $this->assertEquals($gi2->get_name(), $data->grades[2]['item']);
860         $this->assertEquals(3, $data->grades[2]['grade']);
861         $this->assertEquals('Reasonable', $data->grades[2]['grade_formatted']);
862     }
864     public function test_export_data_for_user_about_gradebook_edits() {
865         global $DB;
866         $dg = $this->getDataGenerator();
867         $c1 = $dg->create_course();
868         $c2 = $dg->create_course();
869         $u1 = $dg->create_user();
870         $u2 = $dg->create_user();
871         $u3 = $dg->create_user();
872         $u4 = $dg->create_user();
873         $u5 = $dg->create_user();
874         $u6 = $dg->create_user();
875         $u7 = $dg->create_user();
876         $u8 = $dg->create_user();
877         $u9 = $dg->create_user();
878         $u10 = $dg->create_user();
880         $sysctx = context_system::instance();
881         $u1ctx = context_user::instance($u1->id);
882         $u2ctx = context_user::instance($u2->id);
883         $u3ctx = context_user::instance($u3->id);
884         $u4ctx = context_user::instance($u4->id);
885         $u5ctx = context_user::instance($u5->id);
886         $u6ctx = context_user::instance($u6->id);
887         $c1ctx = context_course::instance($c1->id);
888         $c2ctx = context_course::instance($c2->id);
890         $rootpath = [get_string('grades', 'core_grades')];
891         $relatedtomepath = array_merge($rootpath, [get_string('privacy:path:relatedtome', 'core_grades')]);
892         $allcontexts = [$sysctx->id, $c1ctx->id, $c2ctx->id, $u1ctx->id, $u2ctx->id, $u3ctx->id, $u4ctx->id,
893             $u5ctx->id, $u6ctx->id];
894         $updateactionstr = get_string('privacy:request:historyactionupdate', 'core_grades');
896         // Create some stuff.
897         $gi1a = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
898         $gi1b = new grade_item($dg->create_grade_item(['courseid' => $c1->id]), false);
899         $gi2a = new grade_item($dg->create_grade_item(['courseid' => $c2->id]), false);
900         $gc1a = new grade_category($dg->create_grade_category(['courseid' => $c1->id]), false);
901         $gc1b = new grade_category($dg->create_grade_category(['courseid' => $c1->id]), false);
902         $gc2a = new grade_category($dg->create_grade_category(['courseid' => $c2->id]), false);
903         $go2 = new grade_outcome($dg->create_grade_outcome(['courseid' => $c2->id, 'shortname' => 'go2',
904             'fullname' => 'go2']), false);
906         $go0 = new grade_outcome(['shortname' => 'go0', 'fullname' => 'go0', 'usermodified' => $u1->id]);
907         $go0->insert();
908         $go1 = new grade_outcome(['shortname' => 'go1', 'fullname' => 'go1', 'courseid' => $c1->id, 'usermodified' => $u1->id]);
909         $go1->insert();
911         // Create scales.
912         $s1 = new grade_scale(['name' => 's1', 'scale' => 'a,b', 'userid' => $u7->id, 'courseid' => 0, 'description' => '']);
913         $s1->insert();
914         $s2 = new grade_scale(['name' => 's2', 'scale' => 'a,b', 'userid' => $u8->id, 'courseid' => $c1->id, 'description' => '']);
915         $s2->insert();
916         $s3 = new grade_scale(['name' => 's3', 'scale' => 'a,b', 'userid' => $u8->id, 'courseid' => $c2->id, 'description' => '']);
917         $s3->insert();
919         // User 2 creates history.
920         $this->setUser($u2);
921         $go0->shortname .= ' edited';
922         $go0->update();
923         $gc1a->fullname .= ' edited';
924         $gc1a->update();
926         // User 3 creates history.
927         $this->setUser($u3);
928         $go1->shortname .= ' edited';
929         $go1->update();
930         $gc2a->fullname .= ' a';
931         $gc2a->update();
933         // User 4 updates an outcome in course (creates history).
934         $this->setUser($u4);
935         $go2->shortname .= ' edited';
936         $go2->update();
938         // User 5 updates an item.
939         $this->setUser($u5);
940         $gi1a->itemname .= ' edited';
941         $gi1a->update();
943         // User 6 creates history.
944         $this->setUser($u6);
945         $gi2a->delete();
947         // User 9 creates history.
948         $this->setUser($u9);
949         $s1->name .= ' edited';
950         $s1->update();
952         // User 10 creates history.
953         $this->setUser($u10);
954         $s3->delete();
956         $this->setAdminUser();
958         // Export data for u1.
959         writer::reset();
960         provider::export_user_data(new approved_contextlist($u1, 'core_grades', $allcontexts));
961         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'outcomes');
962         $this->assertCount(1, $data->outcomes);
963         $this->assertEquals($go0->shortname, $data->outcomes[0]['shortname']);
964         $this->assertEquals($go0->fullname, $data->outcomes[0]['fullname']);
965         $this->assertEquals(transform::yesno(true), $data->outcomes[0]['created_or_modified_by_you']);
966         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'outcomes');
967         $this->assertCount(1, $data->outcomes);
968         $this->assertEquals($go1->shortname, $data->outcomes[0]['shortname']);
969         $this->assertEquals($go1->fullname, $data->outcomes[0]['fullname']);
970         $this->assertEquals(transform::yesno(true), $data->outcomes[0]['created_or_modified_by_you']);
971         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'outcomes_history');
972         $this->assertEmpty($data);
973         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'outcomes_history');
974         $this->assertEmpty($data);
976         // Export data for u2.
977         writer::reset();
978         provider::export_user_data(new approved_contextlist($u2, 'core_grades', $allcontexts));
979         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'outcomes');
980         $this->assertEmpty($data);
981         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'outcomes');
982         $this->assertEmpty($data);
983         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'outcomes_history');
984         $this->assertCount(1, $data->modified_records);
985         $this->assertEquals($go0->shortname, $data->modified_records[0]['shortname']);
986         $this->assertEquals($go0->fullname, $data->modified_records[0]['fullname']);
987         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['logged_in_user_was_you']);
988         $this->assertEquals($updateactionstr, $data->modified_records[0]['action']);
990         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'categories_history');
991         $this->assertCount(1, $data->modified_records);
992         $this->assertEquals($gc1a->fullname, $data->modified_records[0]['name']);
993         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['logged_in_user_was_you']);
994         $this->assertEquals($updateactionstr, $data->modified_records[0]['action']);
996         // Export data for u3.
997         writer::reset();
998         provider::export_user_data(new approved_contextlist($u3, 'core_grades', $allcontexts));
999         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'outcomes_history');
1000         $this->assertCount(1, $data->modified_records);
1001         $this->assertEquals($go1->shortname, $data->modified_records[0]['shortname']);
1002         $this->assertEquals($go1->fullname, $data->modified_records[0]['fullname']);
1003         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['logged_in_user_was_you']);
1004         $this->assertEquals($updateactionstr, $data->modified_records[0]['action']);
1006         $data = writer::with_context($c2ctx)->get_related_data($relatedtomepath, 'categories_history');
1007         $this->assertCount(1, $data->modified_records);
1008         $this->assertEquals($gc2a->fullname, $data->modified_records[0]['name']);
1009         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['logged_in_user_was_you']);
1010         $this->assertEquals($updateactionstr, $data->modified_records[0]['action']);
1012         // Export data for u4.
1013         writer::reset();
1014         provider::export_user_data(new approved_contextlist($u4, 'core_grades', $allcontexts));
1015         $data = writer::with_context($c2ctx)->get_related_data($relatedtomepath, 'outcomes_history');
1016         $this->assertCount(1, $data->modified_records);
1017         $this->assertEquals($go2->shortname, $data->modified_records[0]['shortname']);
1018         $this->assertEquals($go2->fullname, $data->modified_records[0]['fullname']);
1019         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['logged_in_user_was_you']);
1020         $this->assertEquals($updateactionstr, $data->modified_records[0]['action']);
1022         // Export data for u5.
1023         writer::reset();
1024         provider::export_user_data(new approved_contextlist($u5, 'core_grades', $allcontexts));
1025         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'items_history');
1026         $this->assertCount(1, $data->modified_records);
1027         $this->assertEquals($gi1a->itemname, $data->modified_records[0]['name']);
1028         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['logged_in_user_was_you']);
1029         $this->assertEquals($updateactionstr, $data->modified_records[0]['action']);
1031         // Export data for u6.
1032         writer::reset();
1033         provider::export_user_data(new approved_contextlist($u6, 'core_grades', $allcontexts));
1034         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'items_history');
1035         $this->assertEmpty($data);
1036         $data = writer::with_context($c2ctx)->get_related_data($relatedtomepath, 'items_history');
1037         $this->assertCount(1, $data->modified_records);
1038         $this->assertEquals($gi2a->itemname, $data->modified_records[0]['name']);
1039         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['logged_in_user_was_you']);
1040         $this->assertEquals(get_string('privacy:request:historyactiondelete', 'core_grades'),
1041             $data->modified_records[0]['action']);
1043         // Export data for u7.
1044         writer::reset();
1045         provider::export_user_data(new approved_contextlist($u7, 'core_grades', $allcontexts));
1046         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'scales');
1047         $this->assertEmpty($data);
1048         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'scales');
1049         $this->assertCount(1, $data->scales);
1050         $this->assertEquals($s1->name, $data->scales[0]['name']);
1051         $this->assertEquals(transform::yesno(true), $data->scales[0]['created_or_modified_by_you']);
1053         // Export data for u8.
1054         writer::reset();
1055         provider::export_user_data(new approved_contextlist($u8, 'core_grades', $allcontexts));
1056         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'scales');
1057         $this->assertEmpty($data);
1058         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'scales');
1059         $this->assertCount(1, $data->scales);
1060         $this->assertEquals($s2->name, $data->scales[0]['name']);
1061         $this->assertEquals(transform::yesno(true), $data->scales[0]['created_or_modified_by_you']);
1062         $data = writer::with_context($c2ctx)->get_related_data($relatedtomepath, 'scales_history');
1063         $this->assertCount(2, $data->modified_records);
1064         $this->assertEquals($s3->name, $data->modified_records[0]['name']);
1065         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['author_of_change_was_you']);
1066         $this->assertEquals(transform::yesno(false), $data->modified_records[0]['author_of_action_was_you']);
1067         $this->assertEquals(get_string('privacy:request:historyactioninsert', 'core_grades'),
1068             $data->modified_records[0]['action']);
1069         $this->assertEquals($s3->name, $data->modified_records[1]['name']);
1070         $this->assertEquals(transform::yesno(true), $data->modified_records[1]['author_of_change_was_you']);
1071         $this->assertEquals(transform::yesno(false), $data->modified_records[1]['author_of_action_was_you']);
1072         $this->assertEquals(get_string('privacy:request:historyactiondelete', 'core_grades'),
1073             $data->modified_records[1]['action']);
1075         // Export data for u9.
1076         writer::reset();
1077         provider::export_user_data(new approved_contextlist($u9, 'core_grades', $allcontexts));
1078         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'scales');
1079         $this->assertEmpty($data);
1080         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'scales');
1081         $this->assertEmpty($data);
1082         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'scales_history');
1083         $this->assertCount(1, $data->modified_records);
1084         $this->assertEquals($s1->name, $data->modified_records[0]['name']);
1085         $this->assertEquals(transform::yesno(false), $data->modified_records[0]['author_of_change_was_you']);
1086         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['author_of_action_was_you']);
1087         $this->assertEquals(get_string('privacy:request:historyactionupdate', 'core_grades'),
1088             $data->modified_records[0]['action']);
1090         // Export data for u10.
1091         writer::reset();
1092         provider::export_user_data(new approved_contextlist($u10, 'core_grades', $allcontexts));
1093         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'scales');
1094         $this->assertEmpty($data);
1095         $data = writer::with_context($c2ctx)->get_related_data($relatedtomepath, 'scales');
1096         $this->assertEmpty($data);
1097         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'scales');
1098         $this->assertEmpty($data);
1099         $data = writer::with_context($c1ctx)->get_related_data($relatedtomepath, 'scales_history');
1100         $this->assertEmpty($data);
1101         $data = writer::with_context($sysctx)->get_related_data($relatedtomepath, 'scales_history');
1102         $this->assertEmpty($data);
1103         $data = writer::with_context($c2ctx)->get_related_data($relatedtomepath, 'scales_history');
1104         $this->assertCount(1, $data->modified_records);
1105         $this->assertEquals($s3->name, $data->modified_records[0]['name']);
1106         $this->assertEquals(transform::yesno(false), $data->modified_records[0]['author_of_change_was_you']);
1107         $this->assertEquals(transform::yesno(true), $data->modified_records[0]['author_of_action_was_you']);
1108         $this->assertEquals(get_string('privacy:request:historyactiondelete', 'core_grades'),
1109             $data->modified_records[0]['action']);
1110     }
1112     /**
1113      * Assert there is no grade data in the context.
1114      *
1115      * @param context $context The context.
1116      * @return void
1117      */
1118     protected function assert_context_has_no_data(context $context) {
1119         $rootpath = [get_string('grades', 'core_grades')];
1120         $relatedtomepath = array_merge($rootpath, [get_string('privacy:path:relatedtome', 'core_grades')]);
1122         $data = writer::with_context($context)->get_data($rootpath);
1123         $this->assertEmpty($data);
1125         $data = writer::with_context($context)->get_related_data($rootpath, 'history');
1126         $this->assertEmpty($data);
1128         $files = ['categories_history', 'items_history', 'outcomes', 'outcomes_history', 'grades', 'grades_history', 'history'];
1129         foreach ($files as $file) {
1130             $data = writer::with_context($context)->get_related_data($relatedtomepath, $file);
1131             $this->assertEmpty($data);
1132         }
1133     }