MDL-62289 tool_dataprivacy: Ensure all user data deleted.
[moodle.git] / admin / tool / dataprivacy / tests / expired_contexts_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  * Expired contexts tests.
19  *
20  * @package    tool_dataprivacy
21  * @copyright  2018 David Monllao
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 use tool_dataprivacy\api;
26 use tool_dataprivacy\data_registry;
27 use tool_dataprivacy\expired_context;
29 defined('MOODLE_INTERNAL') || die();
30 global $CFG;
32 /**
33  * Expired contexts tests.
34  *
35  * @package    tool_dataprivacy
36  * @copyright  2018 David Monllao
37  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  */
39 class tool_dataprivacy_expired_contexts_testcase extends advanced_testcase {
41     /**
42      * setUp.
43      */
44     public function setUp() {
45         $this->resetAfterTest();
46         $this->setAdminUser();
47     }
49     /**
50      * Test expired users flagging and deletion.
51      *
52      * @return null
53      */
54     public function test_expired_users() {
55         global $DB;
57         $purpose = api::create_purpose((object)['name' => 'p1', 'retentionperiod' => 'PT1H', 'lawfulbases' => 'gdpr_art_6_1_a']);
58         $cat = api::create_category((object)['name' => 'a']);
60         $record = (object)[
61             'purposeid' => $purpose->get('id'),
62             'categoryid' => $cat->get('id'),
63             'contextlevel' => CONTEXT_SYSTEM,
64         ];
65         api::set_contextlevel($record);
66         $record->contextlevel = CONTEXT_USER;
67         api::set_contextlevel($record);
69         $userdata = ['lastaccess' => '123'];
70         $user1 = $this->getDataGenerator()->create_user($userdata);
71         $user2 = $this->getDataGenerator()->create_user($userdata);
72         $user3 = $this->getDataGenerator()->create_user($userdata);
73         $user4 = $this->getDataGenerator()->create_user($userdata);
74         $user5 = $this->getDataGenerator()->create_user();
76         $course1 = $this->getDataGenerator()->create_course();
77         // Old course.
78         $course2 = $this->getDataGenerator()->create_course(['startdate' => '1', 'enddate' => '2']);
79         // Ongoing course.
80         $course3 = $this->getDataGenerator()->create_course(['startdate' => '1', 'enddate' => time() + YEARSECS]);
82         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
83         $this->getDataGenerator()->enrol_user($user2->id, $course2->id, 'student');
84         $this->getDataGenerator()->enrol_user($user3->id, $course2->id, 'student');
85         $this->getDataGenerator()->enrol_user($user4->id, $course3->id, 'student');
87         // Add an activity and some data for user 2.
88         $assignmod = $this->getDataGenerator()->create_module('assign', ['course' => $course2->id]);
89         $data = (object) [
90             'assignment' => $assignmod->id,
91             'userid' => $user2->id,
92             'timecreated' => time(),
93             'timemodified' => time(),
94             'status' => 'new',
95             'groupid' => 0,
96             'attemptnumber' => 0,
97             'latest' => 1,
98         ];
99         $DB->insert_record('assign_submission', $data);
100         // We should have one record in the assign submission table.
101         $this->assertEquals(1, $DB->count_records('assign_submission'));
103         // Users without lastaccess are skipped as well as users enroled in courses with no end date.
104         $expired = new \tool_dataprivacy\expired_user_contexts();
105         $numexpired = $expired->flag_expired();
106         $this->assertEquals(2, $numexpired);
107         $this->assertEquals(2, $DB->count_records('tool_dataprivacy_ctxexpired', ['status' => expired_context::STATUS_EXPIRED]));
109         // Approve user2 to be deleted.
110         $user2ctx = \context_user::instance($user2->id);
111         $expiredctx = expired_context::get_record(['contextid' => $user2ctx->id]);
112         api::set_expired_context_status($expiredctx, expired_context::STATUS_APPROVED);
113         $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxexpired', ['status' => expired_context::STATUS_APPROVED]));
115         // Delete expired contexts.
116         $deleted = $expired->delete();
117         $this->assertEquals(1, $deleted);
118         $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxexpired', ['status' => expired_context::STATUS_EXPIRED]));
119         $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxexpired', ['status' => expired_context::STATUS_CLEANED]));
121         // No new records are generated.
122         $numexpired = $expired->flag_expired();
123         $this->assertEquals(0, $numexpired);
124         $this->assertEquals(2, $DB->count_records('tool_dataprivacy_ctxexpired'));
125         $deleted = $expired->delete();
126         $this->assertEquals(0, $deleted);
128         // No user data left in mod_assign.
129         $this->assertEquals(0, $DB->count_records('assign_submission'));
131         // The user is deleted.
132         $deleteduser = \core_user::get_user($user2->id, 'id, deleted', IGNORE_MISSING);
133         $this->assertEquals(1, $deleteduser->deleted);
134     }
136     /**
137      * Test expired course and course stuff flagging and deletion.
138      *
139      * @return null
140      */
141     public function test_expired_course_related_contexts() {
142         global $DB;
144         $purpose1 = api::create_purpose((object)['name' => 'p1', 'retentionperiod' => 'PT1H', 'lawfulbases' => 'gdpr_art_6_1_a']);
145         $purpose2 = api::create_purpose((object)['name' => 'p1', 'retentionperiod' => 'P1000Y', 'lawfulbases' => 'gdpr_art_6_1_b']);
146         $cat = api::create_category((object)['name' => 'a']);
148         $record = (object)[
149             'purposeid' => $purpose1->get('id'),
150             'categoryid' => $cat->get('id'),
151             'contextlevel' => CONTEXT_SYSTEM,
152         ];
153         api::set_contextlevel($record);
155         list($purposevar, $categoryvar) = data_registry::var_names_from_context(
156             \context_helper::get_class_for_level(CONTEXT_COURSE)
157         );
158         set_config($purposevar, $purpose1->get('id'), 'tool_dataprivacy');
160         // A lot more time for modules.
161         list($purposevar, $categoryvar) = data_registry::var_names_from_context(
162             \context_helper::get_class_for_level(CONTEXT_MODULE)
163         );
164         set_config($purposevar, $purpose2->get('id'), 'tool_dataprivacy');
166         $course1 = $this->getDataGenerator()->create_course();
168         // Old course.
169         $course2 = $this->getDataGenerator()->create_course(['startdate' => '1', 'enddate' => '2']);
170         $forum1 = $this->getDataGenerator()->create_module('forum', array('course' => $course2->id));
171         $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $course2->id));
173         // We want to override this last module instance purpose so we can test that modules are also
174         // returned as expired.
175         $forum2ctx = \context_module::instance($forum2->cmid);
176         $record = (object)[
177             'purposeid' => $purpose1->get('id'),
178             'categoryid' => $cat->get('id'),
179             'contextid' => $forum2ctx->id,
180         ];
181         api::set_context_instance($record);
183         // Ongoing course.
184         $course3 = $this->getDataGenerator()->create_course(['startdate' => '1', 'enddate' => time()]);
185         $forum3 = $this->getDataGenerator()->create_module('forum', array('course' => $course3->id));
187         $expired = new \tool_dataprivacy\expired_course_related_contexts();
188         $numexpired = $expired->flag_expired();
190         // Only 1 module has expired.
191         $this->assertEquals(1, $numexpired);
192         $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxexpired', ['status' => expired_context::STATUS_EXPIRED]));
194         // Add a forum1 override to 1h retention period so both forum1 and course2 are also expired.
195         $forum1ctx = \context_module::instance($forum1->cmid);
196         $record->purposeid = $purpose1->get('id');
197         $record->contextid = $forum1ctx->id;
198         api::set_context_instance($record);
199         $numexpired = $expired->flag_expired();
200         $this->assertEquals(2, $numexpired);
201         $this->assertEquals(3, $DB->count_records('tool_dataprivacy_ctxexpired', ['status' => expired_context::STATUS_EXPIRED]));
203         // Approve forum1 to be deleted.
204         $expiredctx = expired_context::get_record(['contextid' => $forum1ctx->id]);
205         api::set_expired_context_status($expiredctx, expired_context::STATUS_APPROVED);
207         // Delete expired contexts.
208         $deleted = $expired->delete();
209         $this->assertEquals(1, $deleted);
210         $this->assertEquals(1, $DB->count_records('tool_dataprivacy_ctxexpired', ['status' => expired_context::STATUS_CLEANED]));
212         $expiredctx = expired_context::get_record(['contextid' => $forum2ctx->id]);
213         api::set_expired_context_status($expiredctx, expired_context::STATUS_APPROVED);
215         $course2ctx = \context_course::instance($course2->id);
216         $expiredctx = expired_context::get_record(['contextid' => $course2ctx->id]);
217         api::set_expired_context_status($expiredctx, expired_context::STATUS_APPROVED);
219         // Delete expired contexts.
220         $deleted = $expired->delete();
221         $this->assertEquals(2, $deleted);
222         $this->assertEquals(3, $DB->count_records('tool_dataprivacy_ctxexpired', ['status' => expired_context::STATUS_CLEANED]));
224         // No new records are generated.
225         $numexpired = $expired->flag_expired();
226         $this->assertEquals(0, $numexpired);
227         $this->assertEquals(3, $DB->count_records('tool_dataprivacy_ctxexpired'));
228         $deleted = $expired->delete();
229         $this->assertEquals(0, $deleted);
231     }