864da6b9fc98d547c90de6b704dff4ab2a23ccc4
[moodle.git] / grade / grading / 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_grading.
19  *
20  * @package    core_grading
21  * @category   test
22  * @copyright  2018 Sara Arjona <sara@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->dirroot . '/grade/grading/tests/fixtures/marking_guide.php');
31 use \core_privacy\tests\provider_testcase;
32 use \core_privacy\local\request\approved_contextlist;
33 use \core_privacy\local\request\transform;
34 use \core_privacy\local\request\writer;
35 use \core_grading\privacy\provider;
37 /**
38  * Privacy tests for core_grading.
39  *
40  * @copyright  2018 Sara Arjona <sara@moodle.com>
41  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42  */
43 class core_grading_privacy_testcase extends provider_testcase {
45     /** @var stdClass User without data. */
46     protected $user0;
48     /** @var stdClass User with data. */
49     protected $user1;
51     /** @var stdClass User with data. */
52     protected $user2;
54     /** @var context context_module of an activity without grading definitions. */
55     protected $instancecontext0;
57     /** @var context context_module of the activity where the grading definitions are. */
58     protected $instancecontext1;
60     /** @var context context_module of the activity where the grading definitions are. */
61     protected $instancecontext2;
63     /**
64      * Test getting the context for the user ID related to this plugin.
65      */
66     public function test_get_contexts_for_userid() {
67         global $DB;
69         $this->resetAfterTest();
70         $this->grading_setup_test_scenario_data();
71         $this->assertCount(2, $DB->get_records('grading_definitions'));
73         // User1 has created grading definitions for instance1 and instance2.
74         $contextlist = provider::get_contexts_for_userid($this->user1->id);
75         $this->assertCount(2, $contextlist);
76         $this->assertContains($this->instancecontext1->id, $contextlist->get_contextids());
77         $this->assertContains($this->instancecontext2->id, $contextlist->get_contextids());
78         $this->assertNotContains($this->instancecontext0->id, $contextlist->get_contextids());
80         // User2 has only modified grading definitions for instance2.
81         $contextlist = provider::get_contexts_for_userid($this->user2->id);
82         $this->assertCount(1, $contextlist);
83         $this->assertContains($this->instancecontext2->id, $contextlist->get_contextids());
85         // User0 hasn't created or modified any grading definition.
86         $contextlist = provider::get_contexts_for_userid($this->user0->id);
87         $this->assertCount(0, $contextlist);
88     }
90     /**
91      * Export for a user with no grading definitions created or modified will not have any data exported.
92      */
93     public function test_export_user_data_no_content() {
94         $this->resetAfterTest();
96         $user = $this->getDataGenerator()->create_user();
97         $this->setUser($user);
98         $context = \context_system::instance();
100         $writer = writer::with_context($context);
101         $this->assertFalse($writer->has_any_data());
102         $this->export_context_data_for_user($user->id, $context, 'core_grading');
103         $this->assertFalse(writer::with_context($context)->has_any_data());
104     }
106     /**
107      * Test that data is exported correctly for this plugin.
108      */
109     public function test_export_user_data() {
110         global $DB;
112         $this->resetAfterTest();
113         $now = time();
114         $defnameprefix = 'fakename';
115         $this->grading_setup_test_scenario_data($defnameprefix, $now);
116         $this->assertCount(2, $DB->get_records('grading_definitions'));
118         // Validate exported data: instance1 - user0 has NO data.
119         $this->setUser($this->user0);
120         writer::reset();
121         $writer = writer::with_context($this->instancecontext1);
122         $this->assertFalse($writer->has_any_data());
123         $this->export_context_data_for_user($this->user0->id, $this->instancecontext1, 'core_grading');
124         $data = $writer->get_data([get_string('gradingmethod', 'grading')]);
125         $this->assertEmpty($data);
127         // Validate exported data: instance0 - user1 has NO data.
128         $this->setUser($this->user1);
129         writer::reset();
130         $writer = writer::with_context($this->instancecontext0);
131         $this->assertFalse($writer->has_any_data());
132         $this->export_context_data_for_user($this->user1->id, $this->instancecontext0, 'core_grading');
133         $data = $writer->get_data([get_string('gradingmethod', 'grading')]);
134         $this->assertEmpty($data);
136         // Validate exported data: instance1 - user1 has data (user has created and modified it).
137         writer::reset();
138         $writer = writer::with_context($this->instancecontext1);
139         $this->assertFalse($writer->has_any_data());
140         $this->export_context_data_for_user($this->user1->id, $this->instancecontext1, 'core_grading');
141         $data = $writer->get_data([get_string('gradingmethod', 'grading')]);
142         $this->assertCount(1, $data->definitions);
144         $firstkey = reset($data->definitions);
145         $this->assertNotEmpty($firstkey->name);
146         $this->assertEquals('test_method', $firstkey->method);
147         $this->assertEquals(transform::datetime($now), $firstkey->timecreated);
148         $this->assertEquals($this->user1->id, $firstkey->usercreated);
149         $this->assertEquals($defnameprefix.'1', $firstkey->name);
151         // Validate exported data: instance2 - user1 has data (user has created it).
152         writer::reset();
153         $writer = writer::with_context($this->instancecontext2);
154         $this->assertFalse($writer->has_any_data());
155         $this->export_context_data_for_user($this->user1->id, $this->instancecontext2, 'core_grading');
156         $data = $writer->get_data([get_string('gradingmethod', 'grading')]);
157         $this->assertCount(1, $data->definitions);
159         $firstkey = reset($data->definitions);
160         $this->assertNotEmpty($firstkey->name);
161         $this->assertEquals('test_method', $firstkey->method);
162         $this->assertEquals(transform::datetime($now), $firstkey->timecreated);
163         $this->assertEquals($this->user1->id, $firstkey->usercreated);
164         $this->assertEquals($defnameprefix.'2', $firstkey->name);
166         // Validate exported data: instance1 - user2 has NO data.
167         $this->setUser($this->user2);
168         writer::reset();
169         $writer = writer::with_context($this->instancecontext1);
170         $this->assertFalse($writer->has_any_data());
171         $this->export_context_data_for_user($this->user2->id, $this->instancecontext1, 'core_grading');
172         $data = $writer->get_data([get_string('gradingmethod', 'grading')]);
173         $this->assertEmpty($data);
175         // Validate exported data: instance2 - user2 has data (user has modified it).
176         $this->setUser($this->user2);
177         writer::reset();
178         $writer = writer::with_context($this->instancecontext2);
179         $this->assertFalse($writer->has_any_data());
180         $this->export_context_data_for_user($this->user2->id, $this->instancecontext2, 'core_grading');
181         $data = $writer->get_data([get_string('gradingmethod', 'grading')]);
182         $this->assertCount(1, $data->definitions);
183     }
185     /**
186      * Test for provider::delete_data_for_all_users_in_context().
187      */
188     public function test_delete_data_for_all_users_in_context() {
189         global $DB;
191         $this->resetAfterTest();
192         $this->grading_setup_test_scenario_data();
194         // Before deletion, we should have 2 grading_definitions.
195         $this->assertCount(2, $DB->get_records('grading_definitions'));
197         // Delete data.
198         provider::delete_data_for_all_users_in_context($this->instancecontext0);
199         provider::delete_data_for_all_users_in_context($this->instancecontext1);
200         provider::delete_data_for_all_users_in_context($this->instancecontext2);
202         // Before deletion, we should have same grading_definitions (nothing was deleted).
203         $this->assertCount(2, $DB->get_records('grading_definitions'));
204     }
206     /**
207      * Test for provider::delete_data_for_user().
208      */
209     public function test_delete_data_for_user() {
210         global $DB;
212         $this->resetAfterTest();
213         $this->grading_setup_test_scenario_data();
215         // Before deletion, we should have 2 grading_definitions.
216         $this->assertCount(2, $DB->get_records('grading_definitions'));
218         // Delete data for $user0.
219         $contextlist = provider::get_contexts_for_userid($this->user0->id);
220         $approvedcontextlist = new approved_contextlist(
221             $this->user0,
222             'core_grading',
223             $contextlist->get_contextids()
224         );
225         provider::delete_data_for_user($approvedcontextlist);
227         // Delete data for $user1.
228         $contextlist = provider::get_contexts_for_userid($this->user1->id);
229         $approvedcontextlist = new approved_contextlist(
230             $this->user1,
231             'core_grading',
232             $contextlist->get_contextids()
233         );
234         provider::delete_data_for_user($approvedcontextlist);
236         // Delete data for $user2.
237         $contextlist = provider::get_contexts_for_userid($this->user2->id);
238         $approvedcontextlist = new approved_contextlist(
239             $this->user2,
240             'core_grading',
241             $contextlist->get_contextids()
242         );
243         provider::delete_data_for_user($approvedcontextlist);
245         // Before deletion, we should have same grading_definitions (nothing was deleted).
246         $this->assertCount(2, $DB->get_records('grading_definitions'));
247     }
249     /**
250      * Test exporting user data relating to an item ID.
251      */
252     public function test_export_item_data() {
253         global $DB;
254         $this->resetAfterTest();
255         $course = $this->getDataGenerator()->create_course();
256         $module = $this->getDataGenerator()->create_module('assign', ['course' => $course]);
257         $user = $this->getDataGenerator()->create_user();
259         $this->setUser($user);
261         $modulecontext = context_module::instance($module->cmid);
262         $guide = new test_guide($modulecontext, 'testrubrib', 'Description text');
263         $guide->add_criteria(
264             'Spelling mistakes',
265             'Full marks will be given for no spelling mistakes.',
266             'Deduct 5 points per spelling mistake made.',
267             25
268         );
269         $guide->add_criteria(
270             'Pictures',
271             'Full marks will be given for including 3 pictures.',
272             'Give 5 points for each picture present',
273             15
274         );
275         $guide->create_guide();
277         $controller = $guide->manager->get_controller('guide');
278         // In the situation of mod_assign this would be the id from assign_grades.
279         $itemid = 1;
280         $instance = $controller->create_instance($user->id, $itemid);
281         // I need the ids for the criteria and there doesn't seem to be a nice method to get it.
282         $criteria = $DB->get_records('gradingform_guide_criteria');
283         $data = ['criteria' => []];
284         foreach ($criteria as $key => $value) {
285             if ($value->shortname == 'Spelling mistakes') {
286                 $data['criteria'][$key]['remark'] = 'This user made several mistakes.';
287                 $data['criteria'][$key]['remarkformat'] = 0;
288                 $data['criteria'][$key]['score'] = 5;
289             } else {
290                 $data['criteria'][$key]['remark'] = 'This user has two pictures.';
291                 $data['criteria'][$key]['remarkformat'] = 0;
292                 $data['criteria'][$key]['score'] = 10;
293             }
294         }
295         $data['itemid'] = $itemid;
297         // Update this instance with data.
298         $instance->update($data);
299         $instanceid = $instance->get_data('id');
301         provider::export_item_data($modulecontext, $itemid, ['Test']);
302         $data = (array) writer::with_context($modulecontext)->get_data(['Test', 'Marking guide', $instanceid]);
303         $this->assertCount(2, $data);
304         $this->assertEquals('This user made several mistakes.', $data['Spelling mistakes']->remark);
305         $this->assertEquals(5, $data['Spelling mistakes']->score);
306         $this->assertEquals('This user has two pictures.', $data['Pictures']->remark);
307         $this->assertEquals(10, $data['Pictures']->score);
308     }
310     /**
311      * Test deleting user data related to a context and item ID.
312      */
313     public function test_delete_instance_data() {
314         global $DB;
315         $this->resetAfterTest();
316         $course = $this->getDataGenerator()->create_course();
317         $module = $this->getDataGenerator()->create_module('assign', ['course' => $course]);
318         $user = $this->getDataGenerator()->create_user();
320         $this->setUser($user);
322         $modulecontext = context_module::instance($module->cmid);
323         $guide = new test_guide($modulecontext, 'testrubrib', 'Description text');
324         $guide->add_criteria(
325             'Spelling mistakes',
326             'Full marks will be given for no spelling mistakes.',
327             'Deduct 5 points per spelling mistake made.',
328             25
329         );
330         $guide->add_criteria(
331             'Pictures',
332             'Full marks will be given for including 3 pictures.',
333             'Give 5 points for each picture present',
334             15
335         );
336         $guide->create_guide();
338         $controller = $guide->manager->get_controller('guide');
339         // In the situation of mod_assign this would be the id from assign_grades.
340         $itemid = 1;
341         $instance = $controller->create_instance($user->id, $itemid);
342         // I need the ids for the criteria and there doesn't seem to be a nice method to get it.
343         $criteria = $DB->get_records('gradingform_guide_criteria');
344         $data = ['criteria' => []];
345         foreach ($criteria as $key => $value) {
346             if ($value->shortname == 'Spelling mistakes') {
347                 $data['criteria'][$key]['remark'] = 'This user made several mistakes.';
348                 $data['criteria'][$key]['remarkformat'] = 0;
349                 $data['criteria'][$key]['score'] = 5;
350             } else {
351                 $data['criteria'][$key]['remark'] = 'This user has two pictures.';
352                 $data['criteria'][$key]['remarkformat'] = 0;
353                 $data['criteria'][$key]['score'] = 10;
354             }
355         }
356         $data['itemid'] = $itemid;
358         // Update this instance with data.
359         $instance->update($data);
361         $itemid = 2;
362         $instance = $controller->create_instance($user->id, $itemid);
363         // I need the ids for the criteria and there doesn't seem to be a nice method to get it.
364         $criteria = $DB->get_records('gradingform_guide_criteria');
365         $data = ['criteria' => []];
366         foreach ($criteria as $key => $value) {
367             if ($value->shortname == 'Spelling mistakes') {
368                 $data['criteria'][$key]['remark'] = 'This user made no mistakes.';
369                 $data['criteria'][$key]['remarkformat'] = 0;
370                 $data['criteria'][$key]['score'] = 25;
371             } else {
372                 $data['criteria'][$key]['remark'] = 'This user has one pictures.';
373                 $data['criteria'][$key]['remarkformat'] = 0;
374                 $data['criteria'][$key]['score'] = 5;
375             }
376         }
377         $data['itemid'] = $itemid;
379         // Update this instance with data.
380         $instance->update($data);
382         // Check how many records we have in the fillings table.
383         $records = $DB->get_records('gradingform_guide_fillings');
384         $this->assertCount(4, $records);
385         // Let's delete one of the instances (the last one would be the easiest).
386         provider::delete_instance_data($modulecontext, $itemid);
387         $records = $DB->get_records('gradingform_guide_fillings');
388         $this->assertCount(2, $records);
389         foreach ($records as $record) {
390             $this->assertNotEquals($instance->get_id(), $record->instanceid);
391         }
392         // This will delete all the rest of the instances for this context.
393         provider::delete_instance_data($modulecontext);
394         $records = $DB->get_records('gradingform_guide_fillings');
395         $this->assertEmpty($records);
396     }
398     /**
399      * Helper function to setup the environment.
400      *
401      * course
402      *  |
403      *  +--instance0 (assignment)
404      *  |   |
405      *  +--instance1 (assignment)
406      *  |   |
407      *  |   +--grading_definition1 (created and modified by user1)
408      *  |   |
409      *  +--instance2 (assignment)
410      *  |   |
411      *  |   +--grading_definition2 (created by user1 and modified by user2)
412      *
413      *
414      * user0 hasn't any data.
415      *
416      * @param string $defnameprefix
417      * @param timestamp $now
418      */
419     protected function grading_setup_test_scenario_data($defnameprefix = null, $now = null) {
420         global $DB;
422         $this->user0 = $this->getDataGenerator()->create_user();
423         $this->user1 = $this->getDataGenerator()->create_user();
424         $this->user2 = $this->getDataGenerator()->create_user();
426         // Create a course.
427         $course = $this->getDataGenerator()->create_course();
428         $coursecontext = context_course::instance($course->id);
430         // Create some assignment instances.
431         $params = (object)array(
432             'course' => $course->id,
433             'name'   => 'Testing instance'
434         );
435         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
436         $instance0 = $generator->create_instance($params);
437         $cm0 = get_coursemodule_from_instance('assign', $instance0->id);
438         $this->instancecontext0 = context_module::instance($cm0->id);
439         $instance1 = $generator->create_instance($params);
440         $cm1 = get_coursemodule_from_instance('assign', $instance1->id);
441         $this->instancecontext1 = context_module::instance($cm1->id);
442         $instance2 = $generator->create_instance($params);
443         $cm2 = get_coursemodule_from_instance('assign', $instance2->id);
444         $this->instancecontext2 = context_module::instance($cm2->id);
446         // Create fake grading areas.
447         $fakearea1 = (object)array(
448             'contextid'    => $this->instancecontext1->id,
449             'component'    => 'mod_assign',
450             'areaname'     => 'submissions',
451             'activemethod' => 'test_method'
452         );
453         $fakeareaid1 = $DB->insert_record('grading_areas', $fakearea1);
454         $fakearea2 = clone($fakearea1);
455         $fakearea2->contextid = $this->instancecontext2->id;
456         $fakeareaid2 = $DB->insert_record('grading_areas', $fakearea2);
458         // Create fake grading definitions.
459         if (empty($now)) {
460             $now = time();
461         }
462         if (empty($defnameprefix)) {
463             $defnameprefix = 'fakename';
464         }
465         $fakedefinition1 = (object)array(
466             'areaid'       => $fakeareaid1,
467             'method'       => 'test_method',
468             'name'         => $defnameprefix.'1',
469             'status'       => 0,
470             'timecreated'  => $now,
471             'usercreated'  => $this->user1->id,
472             'timemodified' => $now + 1,
473             'usermodified' => $this->user1->id,
474         );
475         $fakedefid1 = $DB->insert_record('grading_definitions', $fakedefinition1);
476         $fakedefinition2 = clone($fakedefinition1);
477         $fakedefinition2->areaid = $fakeareaid2;
478         $fakedefinition2->name = $defnameprefix.'2';
479         $fakedefinition2->usermodified = $this->user2->id;
480         $fakedefid2 = $DB->insert_record('grading_definitions', $fakedefinition2);
481     }