Proyectos de Subversion Moodle

Rev

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