Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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/>.
16
 
17
/**
18
 * Data provider tests.
19
 *
20
 * @package    mod_lesson
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
 */
26
namespace mod_lesson\privacy;
27
 
28
defined('MOODLE_INTERNAL') || die();
29
global $CFG;
30
 
31
use core_privacy\tests\provider_testcase;
32
use core_privacy\local\request\approved_contextlist;
33
use core_privacy\local\request\approved_userlist;
34
use core_privacy\local\request\transform;
35
use core_privacy\local\request\writer;
36
use mod_lesson\privacy\provider;
37
 
38
/**
39
 * Data provider testcase class.
40
 *
41
 * @package    mod_lesson
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 provider_test extends provider_testcase {
48
 
49
    public function setUp(): void {
50
        global $PAGE;
51
        $this->setAdminUser();  // The data generator complains without this.
52
        $this->resetAfterTest();
53
        $PAGE->get_renderer('core');
54
    }
55
 
11 efrain 56
    public function test_get_contexts_for_userid(): void {
1 efrain 57
        $dg = $this->getDataGenerator();
58
        $c1 = $dg->create_course();
59
 
60
        $u1 = $dg->create_user();
61
        $u2 = $dg->create_user();
62
        $u3 = $dg->create_user();
63
        $u4 = $dg->create_user();
64
        $u5 = $dg->create_user();
65
        $u6 = $dg->create_user();
66
 
67
        $cm1 = $dg->create_module('lesson', ['course' => $c1]);
68
        $cm2 = $dg->create_module('lesson', ['course' => $c1]);
69
        $cm3 = $dg->create_module('lesson', ['course' => $c1]);
70
        $cm1ctx = \context_module::instance($cm1->cmid);
71
        $cm2ctx = \context_module::instance($cm2->cmid);
72
        $cm3ctx = \context_module::instance($cm3->cmid);
73
 
74
        $this->create_attempt($cm1, $u1);
75
        $this->create_grade($cm2, $u2);
76
        $this->create_timer($cm3, $u3);
77
        $this->create_branch($cm2, $u4);
78
        $this->create_override($cm1, $u5);
79
 
80
        $this->create_attempt($cm2, $u6);
81
        $this->create_grade($cm2, $u6);
82
        $this->create_timer($cm1, $u6);
83
        $this->create_branch($cm2, $u6);
84
        $this->create_override($cm3, $u6);
85
 
86
        $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids();
87
        $this->assertCount(1, $contextids);
88
        $this->assertTrue(in_array($cm1ctx->id, $contextids));
89
 
90
        $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids();
91
        $this->assertCount(1, $contextids);
92
        $this->assertTrue(in_array($cm2ctx->id, $contextids));
93
 
94
        $contextids = provider::get_contexts_for_userid($u3->id)->get_contextids();
95
        $this->assertCount(1, $contextids);
96
        $this->assertTrue(in_array($cm3ctx->id, $contextids));
97
 
98
        $contextids = provider::get_contexts_for_userid($u4->id)->get_contextids();
99
        $this->assertCount(1, $contextids);
100
        $this->assertTrue(in_array($cm2ctx->id, $contextids));
101
 
102
        $contextids = provider::get_contexts_for_userid($u5->id)->get_contextids();
103
        $this->assertCount(1, $contextids);
104
        $this->assertTrue(in_array($cm1ctx->id, $contextids));
105
 
106
        $contextids = provider::get_contexts_for_userid($u6->id)->get_contextids();
107
        $this->assertCount(3, $contextids);
108
        $this->assertTrue(in_array($cm1ctx->id, $contextids));
109
        $this->assertTrue(in_array($cm2ctx->id, $contextids));
110
        $this->assertTrue(in_array($cm3ctx->id, $contextids));
111
    }
112
 
113
    /*
114
     * Test for provider::get_users_in_context().
115
     */
11 efrain 116
    public function test_get_users_in_context(): void {
1 efrain 117
        $dg = $this->getDataGenerator();
118
        $c1 = $dg->create_course();
119
        $component = 'mod_lesson';
120
 
121
        $u1 = $dg->create_user();
122
        $u2 = $dg->create_user();
123
        $u3 = $dg->create_user();
124
        $u4 = $dg->create_user();
125
        $u5 = $dg->create_user();
126
        $u6 = $dg->create_user();
127
 
128
        $cm1 = $dg->create_module('lesson', ['course' => $c1]);
129
        $cm2 = $dg->create_module('lesson', ['course' => $c1]);
130
 
131
        $cm1ctx = \context_module::instance($cm1->cmid);
132
        $cm2ctx = \context_module::instance($cm2->cmid);
133
 
134
        $this->create_attempt($cm1, $u1);
135
        $this->create_grade($cm1, $u2);
136
        $this->create_timer($cm1, $u3);
137
        $this->create_branch($cm1, $u4);
138
        $this->create_override($cm1, $u5);
139
 
140
        $this->create_attempt($cm2, $u6);
141
        $this->create_grade($cm2, $u6);
142
        $this->create_timer($cm2, $u6);
143
        $this->create_branch($cm2, $u6);
144
        $this->create_override($cm2, $u6);
145
 
146
        $context = \context_module::instance($cm1->cmid);
147
        $userlist = new \core_privacy\local\request\userlist($context, $component);
148
        provider::get_users_in_context($userlist);
149
        $userids = $userlist->get_userids();
150
 
151
        $this->assertCount(5, $userids);
152
        $expected = [$u1->id, $u2->id, $u3->id, $u4->id, $u5->id];
153
        $actual = $userids;
154
        sort($expected);
155
        sort($actual);
156
        $this->assertEquals($expected, $actual);
157
 
158
        $context = \context_module::instance($cm2->cmid);
159
        $userlist = new \core_privacy\local\request\userlist($context, $component);
160
        provider::get_users_in_context($userlist);
161
        $userids = $userlist->get_userids();
162
 
163
        $this->assertCount(1, $userids);
164
        $this->assertEquals([$u6->id], $userids);
165
    }
166
 
11 efrain 167
    public function test_delete_data_for_all_users_in_context(): void {
1 efrain 168
        global $DB;
169
        $dg = $this->getDataGenerator();
170
        $c1 = $dg->create_course();
171
        $u1 = $dg->create_user();
172
        $u2 = $dg->create_user();
173
 
174
        $cm1 = $dg->create_module('lesson', ['course' => $c1]);
175
        $cm2 = $dg->create_module('lesson', ['course' => $c1]);
176
        $cm3 = $dg->create_module('lesson', ['course' => $c1]);
177
 
178
        $c1ctx = \context_course::instance($c1->id);
179
        $cm1ctx = \context_module::instance($cm1->cmid);
180
        $cm2ctx = \context_module::instance($cm2->cmid);
181
        $cm3ctx = \context_module::instance($cm3->cmid);
182
 
183
        $this->create_attempt($cm1, $u1);
184
        $this->create_grade($cm1, $u1);
185
        $this->create_timer($cm1, $u1);
186
        $this->create_branch($cm1, $u1);
187
        $this->create_override($cm1, $u1);
188
 
189
        $this->create_attempt($cm1, $u2);
190
        $this->create_grade($cm1, $u2);
191
        $this->create_timer($cm1, $u2);
192
        $this->create_branch($cm1, $u2);
193
        $this->create_override($cm1, $u2);
194
 
195
        $this->create_attempt($cm2, $u1);
196
        $this->create_grade($cm2, $u1);
197
        $this->create_timer($cm2, $u1);
198
        $this->create_branch($cm2, $u1);
199
        $this->create_override($cm2, $u1);
200
        $this->create_attempt($cm2, $u2);
201
        $this->create_grade($cm2, $u2);
202
        $this->create_timer($cm2, $u2);
203
        $this->create_branch($cm2, $u2);
204
        $this->create_override($cm2, $u2);
205
 
206
        $assertcm1nochange = function() use ($DB, $u1, $u2, $cm1) {
207
            $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
208
            $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
209
            $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
210
            $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
211
            $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
212
            $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
213
            $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
214
            $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
215
            $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
216
            $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
217
        };
218
        $assertcm2nochange = function() use ($DB, $u1, $u2, $cm2) {
219
            $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
220
            $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
221
            $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
222
            $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
223
            $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
224
            $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
225
            $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
226
            $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
227
            $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
228
            $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
229
        };
230
 
231
        // Confirm existing state.
232
        $assertcm1nochange();
233
        $assertcm2nochange();
234
 
235
        // Delete the course: no change.
236
        provider::delete_data_for_all_users_in_context(\context_course::instance($c1->id));
237
        $assertcm1nochange();
238
        $assertcm2nochange();
239
 
240
        // Delete another module: no change.
241
        provider::delete_data_for_all_users_in_context(\context_module::instance($cm3->cmid));
242
        $assertcm1nochange();
243
        $assertcm2nochange();
244
 
245
        // Delete cm1: no change in cm2.
246
        provider::delete_data_for_all_users_in_context(\context_module::instance($cm1->cmid));
247
        $assertcm2nochange();
248
        $this->assertFalse($DB->record_exists('lesson_attempts', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
249
        $this->assertFalse($DB->record_exists('lesson_grades', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
250
        $this->assertFalse($DB->record_exists('lesson_timer', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
251
        $this->assertFalse($DB->record_exists('lesson_branch', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
252
        $this->assertFalse($DB->record_exists('lesson_overrides', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
253
        $this->assertFalse($DB->record_exists('lesson_attempts', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
254
        $this->assertFalse($DB->record_exists('lesson_grades', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
255
        $this->assertFalse($DB->record_exists('lesson_timer', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
256
        $this->assertFalse($DB->record_exists('lesson_branch', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
257
        $this->assertFalse($DB->record_exists('lesson_overrides', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
258
    }
259
 
11 efrain 260
    public function test_delete_data_for_user(): void {
1 efrain 261
        global $DB;
262
        $dg = $this->getDataGenerator();
263
        $c1 = $dg->create_course();
264
        $u1 = $dg->create_user();
265
        $u2 = $dg->create_user();
266
 
267
        $cm1 = $dg->create_module('lesson', ['course' => $c1]);
268
        $cm2 = $dg->create_module('lesson', ['course' => $c1]);
269
        $cm3 = $dg->create_module('lesson', ['course' => $c1]);
270
 
271
        $c1ctx = \context_course::instance($c1->id);
272
        $cm1ctx = \context_module::instance($cm1->cmid);
273
        $cm2ctx = \context_module::instance($cm2->cmid);
274
        $cm3ctx = \context_module::instance($cm3->cmid);
275
 
276
        $this->create_attempt($cm1, $u1);
277
        $this->create_grade($cm1, $u1);
278
        $this->create_timer($cm1, $u1);
279
        $this->create_branch($cm1, $u1);
280
        $this->create_override($cm1, $u1);
281
        $this->create_attempt($cm1, $u2);
282
        $this->create_grade($cm1, $u2);
283
        $this->create_timer($cm1, $u2);
284
        $this->create_branch($cm1, $u2);
285
        $this->create_override($cm1, $u2);
286
 
287
        $this->create_attempt($cm2, $u1);
288
        $this->create_grade($cm2, $u1);
289
        $this->create_timer($cm2, $u1);
290
        $this->create_branch($cm2, $u1);
291
        $this->create_override($cm2, $u1);
292
        $this->create_attempt($cm2, $u2);
293
        $this->create_grade($cm2, $u2);
294
        $this->create_timer($cm2, $u2);
295
        $this->create_branch($cm2, $u2);
296
        $this->create_override($cm2, $u2);
297
 
298
        $assertu1nochange = function() use ($DB, $u1, $cm1, $cm2) {
299
            $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
300
            $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
301
            $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
302
            $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
303
            $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
304
            $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
305
            $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
306
            $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
307
            $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
308
            $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
309
        };
310
        $assertu2nochange = function() use ($DB, $u2, $cm1, $cm2) {
311
            $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
312
            $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
313
            $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
314
            $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
315
            $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $u2->id, 'lessonid' => $cm1->id]));
316
            $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
317
            $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
318
            $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
319
            $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
320
            $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $u2->id, 'lessonid' => $cm2->id]));
321
        };
322
 
323
        // Confirm existing state.
324
        $assertu1nochange();
325
        $assertu2nochange();
326
 
327
        // Delete the course: no change.
328
        provider::delete_data_for_user(new approved_contextlist($u1, 'mod_lesson', [\context_course::instance($c1->id)->id]));
329
        $assertu1nochange();
330
        $assertu2nochange();
331
 
332
        // Delete another module: no change.
333
        provider::delete_data_for_user(new approved_contextlist($u1, 'mod_lesson', [\context_module::instance($cm3->cmid)->id]));
334
        $assertu1nochange();
335
        $assertu2nochange();
336
 
337
        // Delete u1 in cm1: no change for u2 and in cm2.
338
        provider::delete_data_for_user(new approved_contextlist($u1, 'mod_lesson', [\context_module::instance($cm1->cmid)->id]));
339
        $assertu2nochange();
340
        $this->assertFalse($DB->record_exists('lesson_attempts', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
341
        $this->assertFalse($DB->record_exists('lesson_grades', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
342
        $this->assertFalse($DB->record_exists('lesson_timer', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
343
        $this->assertFalse($DB->record_exists('lesson_branch', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
344
        $this->assertFalse($DB->record_exists('lesson_overrides', ['userid' => $u1->id, 'lessonid' => $cm1->id]));
345
        $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
346
        $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
347
        $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
348
        $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
349
        $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $u1->id, 'lessonid' => $cm2->id]));
350
    }
351
 
352
    /*
353
     * Test for provider::delete_data_for_users().
354
     */
11 efrain 355
    public function test_delete_data_for_users(): void {
1 efrain 356
        global $DB;
357
        $dg = $this->getDataGenerator();
358
        $c1 = $dg->create_course();
359
        $u1 = $dg->create_user();
360
        $u2 = $dg->create_user();
361
 
362
        $cm1 = $dg->create_module('lesson', ['course' => $c1]);
363
        $cm2 = $dg->create_module('lesson', ['course' => $c1]);
364
        $cm3 = $dg->create_module('lesson', ['course' => $c1]);
365
        $context1 = \context_module::instance($cm1->cmid);
366
        $context3 = \context_module::instance($cm3->cmid);
367
 
368
        $this->create_attempt($cm1, $u1);
369
        $this->create_grade($cm1, $u1);
370
        $this->create_timer($cm1, $u1);
371
        $this->create_branch($cm1, $u1);
372
        $this->create_override($cm1, $u1);
373
        $this->create_attempt($cm1, $u2);
374
        $this->create_grade($cm1, $u2);
375
        $this->create_timer($cm1, $u2);
376
        $this->create_branch($cm1, $u2);
377
        $this->create_override($cm1, $u2);
378
 
379
        $this->create_attempt($cm2, $u1);
380
        $this->create_grade($cm2, $u1);
381
        $this->create_timer($cm2, $u1);
382
        $this->create_branch($cm2, $u1);
383
        $this->create_override($cm2, $u1);
384
        $this->create_attempt($cm2, $u2);
385
        $this->create_grade($cm2, $u2);
386
        $this->create_timer($cm2, $u2);
387
        $this->create_branch($cm2, $u2);
388
        $this->create_override($cm2, $u2);
389
 
390
        $assertnochange = function($user, $cm) use ($DB) {
391
            $this->assertTrue($DB->record_exists('lesson_attempts', ['userid' => $user->id, 'lessonid' => $cm->id]));
392
            $this->assertTrue($DB->record_exists('lesson_grades', ['userid' => $user->id, 'lessonid' => $cm->id]));
393
            $this->assertTrue($DB->record_exists('lesson_timer', ['userid' => $user->id, 'lessonid' => $cm->id]));
394
            $this->assertTrue($DB->record_exists('lesson_branch', ['userid' => $user->id, 'lessonid' => $cm->id]));
395
            $this->assertTrue($DB->record_exists('lesson_overrides', ['userid' => $user->id, 'lessonid' => $cm->id]));
396
        };
397
 
398
        $assertdeleted = function($user, $cm) use ($DB) {
399
            $this->assertFalse($DB->record_exists('lesson_attempts', ['userid' => $user->id, 'lessonid' => $cm->id]));
400
            $this->assertFalse($DB->record_exists('lesson_grades', ['userid' => $user->id, 'lessonid' => $cm->id]));
401
            $this->assertFalse($DB->record_exists('lesson_timer', ['userid' => $user->id, 'lessonid' => $cm->id]));
402
            $this->assertFalse($DB->record_exists('lesson_branch', ['userid' => $user->id, 'lessonid' => $cm->id]));
403
            $this->assertFalse($DB->record_exists('lesson_overrides', ['userid' => $user->id, 'lessonid' => $cm->id]));
404
        };
405
 
406
        // Confirm existing state.
407
        $assertnochange($u1, $cm1);
408
        $assertnochange($u1, $cm2);
409
        $assertnochange($u2, $cm1);
410
        $assertnochange($u2, $cm2);
411
 
412
        // Delete another module: no change.
413
        $approveduserlist = new approved_userlist($context3, 'mod_lesson', [$u1->id]);
414
        provider::delete_data_for_users($approveduserlist);
415
 
416
        $assertnochange($u1, $cm1);
417
        $assertnochange($u1, $cm2);
418
        $assertnochange($u2, $cm1);
419
        $assertnochange($u2, $cm2);
420
 
421
        // Delete cm1 for u1: no change for u2 and in cm2.
422
        $approveduserlist = new approved_userlist($context1, 'mod_lesson', [$u1->id]);
423
        provider::delete_data_for_users($approveduserlist);
424
 
425
        $assertdeleted($u1, $cm1);
426
        $assertnochange($u1, $cm2);
427
        $assertnochange($u2, $cm1);
428
        $assertnochange($u2, $cm2);
429
    }
430
 
11 efrain 431
    public function test_export_data_for_user_overrides(): void {
1 efrain 432
        $dg = $this->getDataGenerator();
433
        $c1 = $dg->create_course();
434
        $u1 = $dg->create_user();
435
        $u2 = $dg->create_user();
436
 
437
        $cm1 = $dg->create_module('lesson', ['course' => $c1]);
438
        $cm2 = $dg->create_module('lesson', ['course' => $c1]);
439
        $cm1ctx = \context_module::instance($cm1->cmid);
440
        $cm2ctx = \context_module::instance($cm2->cmid);
441
 
442
        $now = time();
443
        $this->create_override($cm1, $u1); // All null.
444
        $this->create_override($cm2, $u1, [
445
            'available' => $now - 3600,
446
            'deadline' => $now + 3600,
447
            'timelimit' => 123,
448
            'review' => 1,
449
            'maxattempts' => 1,
450
            'retake' => 0,
451
            'password' => '1337 5p34k'
452
        ]);
453
        $this->create_override($cm1, $u2, [
454
            'available' => $now - 1230,
455
            'timelimit' => 456,
456
            'maxattempts' => 5,
457
            'retake' => 1,
458
        ]);
459
 
460
        provider::export_user_data(new approved_contextlist($u1, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
461
        $data = writer::with_context($cm1ctx)->get_data([]);
462
        $this->assertNotEmpty($data);
463
        $data = writer::with_context($cm1ctx)->get_related_data([], 'overrides');
464
        $this->assertNull($data->available);
465
        $this->assertNull($data->deadline);
466
        $this->assertNull($data->timelimit);
467
        $this->assertNull($data->review);
468
        $this->assertNull($data->maxattempts);
469
        $this->assertNull($data->retake);
470
        $this->assertNull($data->password);
471
 
472
        $data = writer::with_context($cm2ctx)->get_data([]);
473
        $this->assertNotEmpty($data);
474
        $data = writer::with_context($cm2ctx)->get_related_data([], 'overrides');
475
        $this->assertEquals(transform::datetime($now - 3600), $data->available);
476
        $this->assertEquals(transform::datetime($now + 3600), $data->deadline);
477
        $this->assertEquals(format_time(123), $data->timelimit);
478
        $this->assertEquals(transform::yesno(true), $data->review);
479
        $this->assertEquals(1, $data->maxattempts);
480
        $this->assertEquals(transform::yesno(false), $data->retake);
481
        $this->assertEquals('1337 5p34k', $data->password);
482
 
483
        writer::reset();
484
        provider::export_user_data(new approved_contextlist($u2, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
485
        $data = writer::with_context($cm1ctx)->get_data([]);
486
        $this->assertNotEmpty($data);
487
        $data = writer::with_context($cm1ctx)->get_related_data([], 'overrides');
488
        $this->assertEquals(transform::datetime($now - 1230), $data->available);
489
        $this->assertNull($data->deadline);
490
        $this->assertEquals(format_time(456), $data->timelimit);
491
        $this->assertNull($data->review);
492
        $this->assertEquals(5, $data->maxattempts);
493
        $this->assertEquals(transform::yesno(true), $data->retake);
494
        $this->assertNull($data->password);
495
 
496
        $data = writer::with_context($cm2ctx)->get_data([]);
497
        $this->assertNotEmpty($data);
498
        $data = writer::with_context($cm2ctx)->get_related_data([], 'overrides');
499
        $this->assertEmpty($data);
500
    }
501
 
11 efrain 502
    public function test_export_data_for_user_grades(): void {
1 efrain 503
        $dg = $this->getDataGenerator();
504
        $c1 = $dg->create_course();
505
        $u1 = $dg->create_user();
506
        $u2 = $dg->create_user();
507
 
508
        $cm1 = $dg->create_module('lesson', ['course' => $c1]);
509
        $cm2 = $dg->create_module('lesson', ['course' => $c1]);
510
        $cm1ctx = \context_module::instance($cm1->cmid);
511
        $cm2ctx = \context_module::instance($cm2->cmid);
512
 
513
        $now = time();
514
        $this->create_grade($cm2, $u1, ['grade' => 33.33, 'completed' => $now - 3600]);
515
        $this->create_grade($cm2, $u1, ['grade' => 50, 'completed' => $now - 1600]);
516
        $this->create_grade($cm2, $u1, ['grade' => 81.23, 'completed' => $now - 100]);
517
        $this->create_grade($cm1, $u2, ['grade' => 99.98, 'completed' => $now - 86400]);
518
 
519
        provider::export_user_data(new approved_contextlist($u1, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
520
        $data = writer::with_context($cm1ctx)->get_related_data([], 'grades');
521
        $this->assertEmpty($data);
522
        $data = writer::with_context($cm2ctx)->get_related_data([], 'grades');
523
        $this->assertNotEmpty($data);
524
        $this->assertCount(3, $data->grades);
525
        $this->assertEquals(33.33, $data->grades[0]->grade);
526
        $this->assertEquals(50, $data->grades[1]->grade);
527
        $this->assertEquals(81.23, $data->grades[2]->grade);
528
        $this->assertEquals(transform::datetime($now - 3600), $data->grades[0]->completed);
529
        $this->assertEquals(transform::datetime($now - 1600), $data->grades[1]->completed);
530
        $this->assertEquals(transform::datetime($now - 100), $data->grades[2]->completed);
531
 
532
        writer::reset();
533
        provider::export_user_data(new approved_contextlist($u2, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
534
        $data = writer::with_context($cm2ctx)->get_related_data([], 'grades');
535
        $this->assertEmpty($data);
536
        $data = writer::with_context($cm1ctx)->get_related_data([], 'grades');
537
        $this->assertNotEmpty($data);
538
        $this->assertCount(1, $data->grades);
539
        $this->assertEquals(99.98, $data->grades[0]->grade);
540
        $this->assertEquals(transform::datetime($now - 86400), $data->grades[0]->completed);
541
    }
542
 
11 efrain 543
    public function test_export_data_for_user_timers(): void {
1 efrain 544
        $dg = $this->getDataGenerator();
545
        $c1 = $dg->create_course();
546
        $u1 = $dg->create_user();
547
        $u2 = $dg->create_user();
548
 
549
        $cm1 = $dg->create_module('lesson', ['course' => $c1]);
550
        $cm2 = $dg->create_module('lesson', ['course' => $c1]);
551
        $cm1ctx = \context_module::instance($cm1->cmid);
552
        $cm2ctx = \context_module::instance($cm2->cmid);
553
 
554
        $now = time();
555
        $this->create_timer($cm2, $u1, ['starttime' => $now - 2000, 'lessontime' => $now + 3600, 'completed' => 0,
556
            'timemodifiedoffline' => $now - 7000]);
557
        $this->create_timer($cm2, $u1, ['starttime' => $now - 1000, 'lessontime' => $now + 1600, 'completed' => 0]);
558
        $this->create_timer($cm2, $u1, ['starttime' => $now - 500, 'lessontime' => $now + 100, 'completed' => 1]);
559
        $this->create_timer($cm1, $u2, ['starttime' => $now - 1000, 'lessontime' => $now + 1800, 'completed' => 1]);
560
 
561
        provider::export_user_data(new approved_contextlist($u1, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
562
        $data = writer::with_context($cm1ctx)->get_related_data([], 'timers');
563
        $this->assertEmpty($data);
564
        $data = writer::with_context($cm2ctx)->get_related_data([], 'timers');
565
        $this->assertNotEmpty($data);
566
        $this->assertCount(3, $data->timers);
567
        $this->assertEquals(transform::datetime($now - 2000), $data->timers[0]->starttime);
568
        $this->assertEquals(transform::datetime($now + 3600), $data->timers[0]->lastactivity);
569
        $this->assertEquals(transform::yesno(false), $data->timers[0]->completed);
570
        $this->assertEquals(transform::datetime($now - 7000), $data->timers[0]->timemodifiedoffline);
571
 
572
        $this->assertEquals(transform::datetime($now - 1000), $data->timers[1]->starttime);
573
        $this->assertEquals(transform::datetime($now + 1600), $data->timers[1]->lastactivity);
574
        $this->assertEquals(transform::yesno(false), $data->timers[1]->completed);
575
        $this->assertNull($data->timers[1]->timemodifiedoffline);
576
 
577
        $this->assertEquals(transform::datetime($now - 500), $data->timers[2]->starttime);
578
        $this->assertEquals(transform::datetime($now + 100), $data->timers[2]->lastactivity);
579
        $this->assertEquals(transform::yesno(true), $data->timers[2]->completed);
580
        $this->assertNull($data->timers[2]->timemodifiedoffline);
581
 
582
        writer::reset();
583
        provider::export_user_data(new approved_contextlist($u2, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
584
        $data = writer::with_context($cm2ctx)->get_related_data([], 'timers');
585
        $this->assertEmpty($data);
586
        $data = writer::with_context($cm1ctx)->get_related_data([], 'timers');
587
        $this->assertCount(1, $data->timers);
588
        $this->assertEquals(transform::datetime($now - 1000), $data->timers[0]->starttime);
589
        $this->assertEquals(transform::datetime($now + 1800), $data->timers[0]->lastactivity);
590
        $this->assertEquals(transform::yesno(true), $data->timers[0]->completed);
591
        $this->assertNull($data->timers[0]->timemodifiedoffline);
592
    }
593
 
11 efrain 594
    public function test_export_data_for_user_attempts(): void {
1 efrain 595
        global $DB;
596
        $dg = $this->getDataGenerator();
597
        $lg = $dg->get_plugin_generator('mod_lesson');
598
 
599
        $c1 = $dg->create_course();
600
        $u1 = $dg->create_user();
601
        $u2 = $dg->create_user();
602
 
603
        $cm1 = $dg->create_module('lesson', ['course' => $c1]);
604
        $cm2 = $dg->create_module('lesson', ['course' => $c1]);
605
        $cm1ctx = \context_module::instance($cm1->cmid);
606
        $cm2ctx = \context_module::instance($cm2->cmid);
607
 
608
        $page1 = $lg->create_content($cm1);
609
        $page2 = $lg->create_question_truefalse($cm1);
610
        $page3 = $lg->create_question_multichoice($cm1);
611
        $page4 = $lg->create_question_multichoice($cm1, [
612
            'qoption' => 1,
613
            'answer_editor' => [
614
                ['text' => 'Cats', 'format' => FORMAT_PLAIN, 'score' => 1],
615
                ['text' => 'Dogs', 'format' => FORMAT_PLAIN, 'score' => 1],
616
                ['text' => 'Birds', 'format' => FORMAT_PLAIN, 'score' => 0],
617
            ],
618
            'jumpto' => [LESSON_NEXTPAGE, LESSON_NEXTPAGE, LESSON_THISPAGE]
619
        ]);
620
        $page4answers = array_keys($DB->get_records('lesson_answers', ['pageid' => $page4->id], 'id'));
621
        $page5 = $lg->create_question_matching($cm1, [
622
            'answer_editor' => [
623
                2 => ['text' => 'The plural of cat', 'format' => FORMAT_PLAIN],
624
                3 => ['text' => 'The plural of dog', 'format' => FORMAT_PLAIN],
625
                4 => ['text' => 'The plural of bird', 'format' => FORMAT_PLAIN],
626
            ],
627
            'response_editor' => [
628
                2 => 'Cats',
629
                3 => 'Dogs',
630
                4 => 'Birds',
631
            ]
632
        ]);
633
        $page6 = $lg->create_question_shortanswer($cm1);
634
        $page7 = $lg->create_question_numeric($cm1);
635
        $page8 = $lg->create_question_essay($cm1);
636
        $page9 = $lg->create_content($cm1);
637
 
638
        $pageb1 = $lg->create_content($cm2);
639
        $pageb2 = $lg->create_question_truefalse($cm2);
640
        $pageb3 = $lg->create_question_truefalse($cm2);
641
 
642
        $this->create_branch($cm1, $u1, ['pageid' => $page1->id, 'nextpageid' => $page2->id]);
643
        $this->create_attempt($cm1, $u1, ['pageid' => $page2->id, 'useranswer' => 'This is true']);
644
        $this->create_attempt($cm1, $u1, ['pageid' => $page3->id, 'useranswer' => 'A', 'correct' => 1]);
645
        $this->create_attempt($cm1, $u1, ['pageid' => $page4->id,
646
            'useranswer' => implode(',', array_slice($page4answers, 0, 2))]);
647
        $this->create_attempt($cm1, $u1, ['pageid' => $page5->id, 'useranswer' => 'Cats,Birds,Dogs']);
648
        $this->create_attempt($cm1, $u1, ['pageid' => $page6->id, 'useranswer' => 'Hello world!']);
649
        $this->create_attempt($cm1, $u1, ['pageid' => $page7->id, 'useranswer' => '1337']);
650
        $this->create_attempt($cm1, $u1, ['pageid' => $page8->id, 'useranswer' => serialize((object) [
651
            'sent' => 0, 'graded' => 0, 'score' => 0, 'answer' => 'I like cats', 'answerformat' => FORMAT_PLAIN,
652
            'response' => 'Me too!', 'responseformat' => FORMAT_PLAIN
653
        ])]);
654
        $this->create_branch($cm1, $u1, ['pageid' => $page9->id, 'nextpageid' => 0]);
655
 
656
        provider::export_user_data(new approved_contextlist($u1, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
657
        $data = writer::with_context($cm2ctx)->get_related_data([], 'attempts');
658
        $this->assertEmpty($data);
659
        $data = writer::with_context($cm1ctx)->get_related_data([], 'attempts');
660
        $this->assertNotEmpty($data);
661
        $this->assertCount(1, $data->attempts);
662
        $this->assertEquals(1, $data->attempts[0]->number);
663
        $this->assertCount(2, $data->attempts[0]->jumps);
664
        $this->assertCount(7, $data->attempts[0]->answers);
665
        $jump = $data->attempts[0]->jumps[0];
666
        $this->assert_attempt_page($page1, $jump);
667
        $this->assertTrue(strpos($jump['went_to'], $page2->title) !== false);
668
        $jump = $data->attempts[0]->jumps[1];
669
        $this->assert_attempt_page($page9, $jump);
670
        $this->assertEquals(get_string('endoflesson', 'mod_lesson'), $jump['went_to']);
671
        $answer = $data->attempts[0]->answers[0];
672
        $this->assert_attempt_page($page2, $answer);
673
        $this->assertEquals(transform::yesno(false), $answer['correct']);
674
        $this->assertEquals('This is true', $answer['answer']);
675
        $answer = $data->attempts[0]->answers[1];
676
        $this->assert_attempt_page($page3, $answer);
677
        $this->assertEquals(transform::yesno(true), $answer['correct']);
678
        $this->assertEquals('A', $answer['answer']);
679
        $answer = $data->attempts[0]->answers[2];
680
        $this->assert_attempt_page($page4, $answer);
681
        $this->assertEquals(transform::yesno(false), $answer['correct']);
682
        $this->assertCount(2, $answer['answer']);
683
        $this->assertTrue(in_array('Cats', $answer['answer']));
684
        $this->assertTrue(in_array('Dogs', $answer['answer']));
685
        $answer = $data->attempts[0]->answers[3];
686
        $this->assert_attempt_page($page5, $answer);
687
        $this->assertEquals(transform::yesno(false), $answer['correct']);
688
        $this->assertCount(3, $answer['answer']);
689
        $this->assertEquals('The plural of cat', $answer['answer'][0]['label']);
690
        $this->assertEquals('Cats', $answer['answer'][0]['matched_with']);
691
        $this->assertEquals('The plural of dog', $answer['answer'][1]['label']);
692
        $this->assertEquals('Birds', $answer['answer'][1]['matched_with']);
693
        $this->assertEquals('The plural of bird', $answer['answer'][2]['label']);
694
        $this->assertEquals('Dogs', $answer['answer'][2]['matched_with']);
695
        $answer = $data->attempts[0]->answers[4];
696
        $this->assert_attempt_page($page6, $answer);
697
        $this->assertEquals(transform::yesno(false), $answer['correct']);
698
        $this->assertEquals('Hello world!', $answer['answer']);
699
        $answer = $data->attempts[0]->answers[5];
700
        $this->assert_attempt_page($page7, $answer);
701
        $this->assertEquals(transform::yesno(false), $answer['correct']);
702
        $this->assertEquals('1337', $answer['answer']);
703
        $answer = $data->attempts[0]->answers[6];
704
        $this->assert_attempt_page($page8, $answer);
705
        $this->assertEquals(transform::yesno(false), $answer['correct']);
706
        $this->assertEquals('I like cats', $answer['answer']);
707
        $this->assertEquals('Me too!', $answer['response']);
708
 
709
        writer::reset();
710
        provider::export_user_data(new approved_contextlist($u2, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
711
        $data = writer::with_context($cm1ctx)->get_related_data([], 'attempts');
712
        $this->assertEmpty($data);
713
        $data = writer::with_context($cm2ctx)->get_related_data([], 'attempts');
714
        $this->assertEmpty($data);
715
 
716
        // Let's mess with the data by creating an additional attempt for u1, and create data for u1 and u2 in the other cm.
717
        $this->create_branch($cm1, $u1, ['pageid' => $page1->id, 'nextpageid' => $page3->id, 'retry' => 1]);
718
        $this->create_attempt($cm1, $u1, ['pageid' => $page3->id, 'useranswer' => 'B', 'retry' => 1]);
719
 
720
        $this->create_branch($cm2, $u1, ['pageid' => $pageb1->id, 'nextpageid' => $pageb2->id]);
721
        $this->create_attempt($cm2, $u1, ['pageid' => $pageb2->id, 'useranswer' => 'Abc']);
722
 
723
        $this->create_branch($cm2, $u2, ['pageid' => $pageb1->id, 'nextpageid' => $pageb3->id]);
724
        $this->create_attempt($cm2, $u2, ['pageid' => $pageb3->id, 'useranswer' => 'Def']);
725
 
726
        writer::reset();
727
        provider::export_user_data(new approved_contextlist($u1, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
728
        $data = writer::with_context($cm1ctx)->get_related_data([], 'attempts');
729
        $this->assertNotEmpty($data);
730
        $this->assertCount(2, $data->attempts);
731
        $this->assertEquals(1, $data->attempts[0]->number);
732
        $this->assertCount(2, $data->attempts[0]->jumps);
733
        $this->assertCount(7, $data->attempts[0]->answers);
734
        $attempt = $data->attempts[1];
735
        $this->assertEquals(2, $attempt->number);
736
        $this->assertCount(1, $attempt->jumps);
737
        $this->assertCount(1, $attempt->answers);
738
        $this->assert_attempt_page($page1, $attempt->jumps[0]);
739
        $this->assertTrue(strpos($attempt->jumps[0]['went_to'], $page3->title) !== false);
740
        $this->assert_attempt_page($page3, $attempt->answers[0]);
741
        $this->assertEquals('B', $attempt->answers[0]['answer']);
742
 
743
        $data = writer::with_context($cm2ctx)->get_related_data([], 'attempts');
744
        $this->assertCount(1, $data->attempts);
745
        $attempt = $data->attempts[0];
746
        $this->assertEquals(1, $attempt->number);
747
        $this->assertCount(1, $attempt->jumps);
748
        $this->assertCount(1, $attempt->answers);
749
        $this->assert_attempt_page($pageb1, $attempt->jumps[0]);
750
        $this->assertTrue(strpos($attempt->jumps[0]['went_to'], $pageb2->title) !== false);
751
        $this->assert_attempt_page($pageb2, $attempt->answers[0]);
752
        $this->assertEquals('Abc', $attempt->answers[0]['answer']);
753
 
754
        writer::reset();
755
        provider::export_user_data(new approved_contextlist($u2, 'mod_lesson', [$cm1ctx->id, $cm2ctx->id]));
756
        $data = writer::with_context($cm1ctx)->get_related_data([], 'attempts');
757
        $this->assertEmpty($data);
758
 
759
        $data = writer::with_context($cm2ctx)->get_related_data([], 'attempts');
760
        $this->assertCount(1, $data->attempts);
761
        $attempt = $data->attempts[0];
762
        $this->assertEquals(1, $attempt->number);
763
        $this->assertCount(1, $attempt->jumps);
764
        $this->assertCount(1, $attempt->answers);
765
        $this->assert_attempt_page($pageb1, $attempt->jumps[0]);
766
        $this->assertTrue(strpos($attempt->jumps[0]['went_to'], $pageb3->title) !== false);
767
        $this->assert_attempt_page($pageb3, $attempt->answers[0]);
768
        $this->assertEquals('Def', $attempt->answers[0]['answer']);
769
    }
770
 
771
    /**
772
     * Assert the page details of an attempt.
773
     *
774
     * @param object $page The expected page info.
775
     * @param array $attempt The exported attempt details.
776
     * @return void
777
     */
778
    protected function assert_attempt_page($page, $attempt) {
779
        $this->assertEquals($page->id, $attempt['id']);
780
        $this->assertEquals($page->title, $attempt['page']);
781
        $this->assertEquals(format_text($page->contents, $page->contentsformat), $attempt['contents']);
782
    }
783
 
784
    /**
785
     * Create an attempt (answer to a question).
786
     *
787
     * @param object $lesson The lesson.
788
     * @param object $user The user.
789
     * @param array $options Options.
790
     * @return object
791
     */
792
    protected function create_attempt($lesson, $user, array $options = []) {
793
        global $DB;
794
        $record = (object) array_merge([
795
            'lessonid' => $lesson->id,
796
            'userid' => $user->id,
797
            'pageid' => 0,
798
            'answerid' => 0,
799
            'retry' => 0,
800
            'correct' => 0,
801
            'useranswer' => '',
802
            'timeseen' => time(),
803
        ], $options);
804
        $record->id = $DB->insert_record('lesson_attempts', $record);
805
        return $record;
806
    }
807
 
808
    /**
809
     * Create a grade.
810
     *
811
     * @param object $lesson The lesson.
812
     * @param object $user The user.
813
     * @param array $options Options.
814
     * @return object
815
     */
816
    protected function create_grade($lesson, $user, array $options = []) {
817
        global $DB;
818
        $record = (object) array_merge([
819
            'lessonid' => $lesson->id,
820
            'userid' => $user->id,
821
            'late' => 0,
822
            'grade' => 50.0,
823
            'completed' => time(),
824
        ], $options);
825
        $record->id = $DB->insert_record('lesson_grades', $record);
826
        return $record;
827
    }
828
 
829
    /**
830
     * Create a timer.
831
     *
832
     * @param object $lesson The lesson.
833
     * @param object $user The user.
834
     * @param array $options Options.
835
     * @return object
836
     */
837
    protected function create_timer($lesson, $user, array $options = []) {
838
        global $DB;
839
        $record = (object) array_merge([
840
            'lessonid' => $lesson->id,
841
            'userid' => $user->id,
842
            'starttime' => time() - 600,
843
            'lessontime' => time(),
844
            'completed' => 1,
845
            'timemodifiedoffline' => 0,
846
        ], $options);
847
        $record->id = $DB->insert_record('lesson_timer', $record);
848
        return $record;
849
    }
850
 
851
    /**
852
     * Create a branch (choice on page).
853
     *
854
     * @param object $lesson The lesson.
855
     * @param object $user The user.
856
     * @param array $options Options.
857
     * @return object
858
     */
859
    protected function create_branch($lesson, $user, array $options = []) {
860
        global $DB;
861
        $record = (object) array_merge([
862
            'lessonid' => $lesson->id,
863
            'userid' => $user->id,
864
            'pageid' => 0,
865
            'retry' => 0,
866
            'flag' => 0,
867
            'timeseen' => time(),
868
            'nextpageid' => 0,
869
        ], $options);
870
        $record->id = $DB->insert_record('lesson_branch', $record);
871
        return $record;
872
    }
873
 
874
    /**
875
     * Create an override.
876
     *
877
     * @param object $lesson The lesson.
878
     * @param object $user The user.
879
     * @param array $options Options.
880
     * @return object
881
     */
882
    protected function create_override($lesson, $user, array $options = []) {
883
        global $DB;
884
        $record = (object) array_merge([
885
            'lessonid' => $lesson->id,
886
            'userid' => $user->id,
887
        ], $options);
888
        $record->id = $DB->insert_record('lesson_overrides', $record);
889
        return $record;
890
    }
891
}