Proyectos de Subversion Moodle

Rev

Ir a la última revisión | | 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
namespace tool_uploadcourse;
18
 
19
use tool_uploadcourse_processor;
20
use tool_uploadcourse_course;
21
 
22
/**
23
 * Course test case.
24
 *
25
 * @covers     \tool_uploadcourse_course
26
 * @package    tool_uploadcourse
27
 * @copyright  2013 Frédéric Massart
28
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
29
 */
30
class course_test extends \advanced_testcase {
31
 
32
    /** @var \testing_data_generator $datagenerator */
33
    protected $datagenerator;
34
    /** @var \stdClass $user */
35
    protected $user;
36
 
37
    /**
38
     * Initialise defaults for each testcase.
39
     *
40
     * @param int $roleid
41
     * @throws \coding_exception
42
     */
43
    protected function initialise_test(int $roleid = 1): void {
44
        // Reset the database after test.
45
        $this->resetAfterTest(true);
46
 
47
        // Get a new data generator.
48
        $this->datagenerator = $this->getDataGenerator();
49
 
50
        // Create a user.
51
        $this->prepare_user($roleid);
52
    }
53
 
54
    /**
55
     * Create random user and assign default role Manager (roleid = 1).
56
     *
57
     * @param int $roleid
58
     * @throws \coding_exception
59
     */
60
    protected function prepare_user(int $roleid): void {
61
        // Generate a random user.
62
        $user = $this->datagenerator->create_user();
63
 
64
        // Log the user in (set the $USER global variable).
65
        $this->setUser($user);
66
 
67
        // Assign a role to the current user.
68
        $this->datagenerator->role_assign($roleid, $user->id, false);
69
    }
70
 
71
    public function test_proceed_without_prepare(): void {
72
        $this->initialise_test();
73
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
74
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
75
        $data = array();
76
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
77
        $this->expectException(\coding_exception::class);
78
        $co->proceed();
79
    }
80
 
81
    public function test_proceed_when_prepare_failed() {
82
        $this->initialise_test();
83
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
84
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
85
        $data = array();
86
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
87
        $this->assertFalse($co->prepare());
88
        $this->expectException(\moodle_exception::class);
89
        $co->proceed();
90
    }
91
 
92
    public function test_proceed_when_already_started() {
93
        $this->initialise_test();
94
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
95
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
96
        $data = array('shortname' => 'test', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1);
97
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
98
        $this->assertTrue($co->prepare());
99
        $co->proceed();
100
        $this->expectException('coding_exception');
101
        $co->proceed();
102
    }
103
 
104
    public function test_invalid_shortname() {
105
        $this->initialise_test();
106
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
107
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
108
        $data = array('shortname' => '<invalid>', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1);
109
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
110
        $this->assertFalse($co->prepare());
111
        $this->assertArrayHasKey('invalidshortname', $co->get_errors());
112
    }
113
 
114
    public function test_invalid_shortname_too_long() {
115
        $this->resetAfterTest();
116
 
117
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
118
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
119
 
120
        $upload = new tool_uploadcourse_course($mode, $updatemode, [
121
            'category' => 1,
122
            'fullname' => 'New course',
123
            'shortname' => str_repeat('X', 2000),
124
        ]);
125
 
126
        $this->assertFalse($upload->prepare());
127
        $this->assertArrayHasKey('invalidshortnametoolong', $upload->get_errors());
128
    }
129
 
130
    public function test_invalid_fullname_too_long() {
131
        $this->initialise_test();
132
 
133
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
134
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
135
 
136
        $upload = new tool_uploadcourse_course($mode, $updatemode, [
137
            'category' => 1,
138
            'fullname' => str_repeat('X', 2000),
139
        ]);
140
 
141
        $this->assertFalse($upload->prepare());
142
        $this->assertArrayHasKey('invalidfullnametoolong', $upload->get_errors());
143
    }
144
 
145
    public function test_invalid_visibility() {
146
        $this->initialise_test();
147
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
148
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
149
        $data = array('shortname' => 'test', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1, 'visible' => 2);
150
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
151
        $this->assertFalse($co->prepare());
152
        $this->assertArrayHasKey('invalidvisibilitymode', $co->get_errors());
153
    }
154
 
155
    /**
156
     * Test setting 'downloadcontent' field when the feature is globally disabled
157
     */
158
    public function test_downloadcontent_disabled(): void {
159
        $this->resetAfterTest();
160
        $this->setAdminUser();
161
 
162
        set_config('downloadcoursecontentallowed', 0);
163
 
164
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
165
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
166
 
167
        $upload = new tool_uploadcourse_course($mode, $updatemode, [
168
            'category' => 1,
169
            'fullname' => 'Testing',
170
            'shortname' => 'T101',
171
            'downloadcontent' => DOWNLOAD_COURSE_CONTENT_ENABLED,
172
        ]);
173
 
174
        $this->assertFalse($upload->prepare());
175
        $this->assertArrayHasKey('downloadcontentnotallowed', $upload->get_errors());
176
    }
177
 
178
    /**
179
     * Test setting 'downloadcontent' field when user doesn't have required capability
180
     */
181
    public function test_downloadcontent_capability(): void {
182
        global $DB;
183
 
184
        $this->resetAfterTest();
185
 
186
        set_config('downloadcoursecontentallowed', 1);
187
 
188
        // Create category in which to create the new course.
189
        $category = $this->getDataGenerator()->create_category();
190
        $categorycontext = \context_coursecat::instance($category->id);
191
 
192
        $user = $this->getDataGenerator()->create_user();
193
        $this->setUser($user);
194
 
195
        // Assign the user as a manager of the category, disable ability to configure course content download.
196
        $roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
197
        role_assign($roleid, $user->id, $categorycontext);
198
        role_change_permission($roleid, $categorycontext, 'moodle/course:configuredownloadcontent', CAP_PROHIBIT);
199
 
200
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
201
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
202
 
203
        $upload = new tool_uploadcourse_course($mode, $updatemode, [
204
            'category' => $category->id,
205
            'fullname' => 'Testing',
206
            'shortname' => 'T101',
207
            'downloadcontent' => DOWNLOAD_COURSE_CONTENT_ENABLED,
208
        ]);
209
 
210
        $this->assertFalse($upload->prepare());
211
        $this->assertArrayHasKey('downloadcontentnotallowed', $upload->get_errors());
212
    }
213
 
214
    /**
215
     * Test setting 'downloadcontent' field to an invalid value
216
     */
217
    public function test_downloadcontent_invalid(): void {
218
        $this->resetAfterTest();
219
        $this->setAdminUser();
220
 
221
        set_config('downloadcoursecontentallowed', 1);
222
 
223
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
224
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
225
 
226
        $upload = new tool_uploadcourse_course($mode, $updatemode, [
227
            'category' => 1,
228
            'fullname' => 'Testing',
229
            'shortname' => 'T101',
230
            'downloadcontent' => 42,
231
        ]);
232
 
233
        $this->assertFalse($upload->prepare());
234
        $this->assertArrayHasKey('invaliddownloadcontent', $upload->get_errors());
235
    }
236
 
237
    /**
238
     * Test a role's capability to use the upload course tool.
239
     *
240
     * @covers \permissions::check_permission_to_use_uploadcourse_tool
241
     */
242
    public function test_invalid_role(): void {
243
        global $DB;
244
 
245
        $rolesallowed = ['manager'];
246
        $roles = get_all_roles();
247
 
248
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
249
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
250
 
251
        foreach ($roles as $role) {
252
            $this->initialise_test($role->id);
253
 
254
            $data = ['shortname' => 'newcourse', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1];
255
            $co = new tool_uploadcourse_course($mode, $updatemode, $data);
256
 
257
            if (in_array($role->archetype, $rolesallowed)) {
258
                $this->assertTrue($co->prepare());
259
                $co->proceed();
260
                $courseid = $DB->get_field('course', 'id', ['shortname' => 'newcourse'], MUST_EXIST);
261
                $this->assertEquals(0, course_get_format($courseid)->get_course()->coursedisplay);
262
 
263
                // Delete course for next assertion.
264
                $importoptions = ['candelete' => true];
265
                $data = ['shortname' => 'newcourse', 'delete' => 1];
266
                $co = new tool_uploadcourse_course($mode, $updatemode, $data, [], $importoptions);
267
                $this->assertTrue($co->prepare());
268
                $co->proceed();
269
            } else {
270
                $this->assertFalse($co->prepare());
271
                $this->assertArrayHasKey('courseuploadnotallowed', $co->get_errors());
272
            }
273
        }
274
    }
275
 
276
    public function test_create() {
277
        global $DB;
278
        $this->initialise_test();
279
 
280
        // Existing course.
281
        $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1', 'summary' => 'Yay!'));
282
        $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
283
 
284
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
285
 
286
        // Try to add a new course.
287
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
288
        $data = array('shortname' => 'newcourse', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1);
289
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
290
        $this->assertTrue($co->prepare());
291
        $this->assertFalse($DB->record_exists('course', array('shortname' => 'newcourse')));
292
        $co->proceed();
293
        $course = $DB->get_record('course', array('shortname' => 'newcourse'), '*', MUST_EXIST);
294
        $this->assertEquals(0, course_get_format($course)->get_course()->coursedisplay);
295
 
296
        // Try to add a new course, that already exists.
297
        $coursecount = $DB->count_records('course', array());
298
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
299
        $data = array('shortname' => 'c1', 'fullname' => 'C1FN', 'summary' => 'C1', 'category' => 1);
300
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
301
        $this->assertFalse($co->prepare());
302
        $this->assertArrayHasKey('courseexistsanduploadnotallowed', $co->get_errors());
303
        $this->assertEquals($coursecount, $DB->count_records('course', array()));
304
        $this->assertNotEquals('C1', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
305
 
306
        // Try to add new with shortname incrementation.
307
        $mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
308
        $data = array('shortname' => 'c1', 'fullname' => 'C1FN', 'summary' => 'C1', 'category' => 1);
309
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
310
        $this->assertTrue($co->prepare());
311
        $co->proceed();
312
        $this->assertTrue($DB->record_exists('course', array('shortname' => 'c2')));
313
 
314
        // Add a new course with non-default course format option.
315
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
316
        $data = array('shortname' => 'c3', 'fullname' => 'C3', 'summary' => 'New c3', 'category' => 1,
317
            'format' => 'weeks', 'coursedisplay' => 1);
318
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
319
        $this->assertTrue($co->prepare());
320
        $co->proceed();
321
        $course = $DB->get_record('course', array('shortname' => 'c3'), '*', MUST_EXIST);
322
        $this->assertEquals(1, course_get_format($course)->get_course()->coursedisplay);
323
    }
324
 
325
    public function test_create_with_sections() {
326
        global $DB;
327
        $this->initialise_test();
328
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
329
        $defaultnumsections = get_config('moodlecourse', 'numsections');
330
 
331
        // Add new course, make sure default number of sections is created.
332
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
333
        $data = array('shortname' => 'newcourse1', 'fullname' => 'New course1', 'format' => 'topics', 'category' => 1);
334
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
335
        $this->assertTrue($co->prepare());
336
        $co->proceed();
337
        $courseid = $DB->get_field('course', 'id', array('shortname' => 'newcourse1'));
338
        $this->assertNotEmpty($courseid);
339
        $this->assertEquals($defaultnumsections + 1,
340
            $DB->count_records('course_sections', ['course' => $courseid]));
341
 
342
        // Add new course specifying number of sections.
343
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
344
        $data = array('shortname' => 'newcourse2', 'fullname' => 'New course2', 'format' => 'topics', 'category' => 1,
345
            'numsections' => 15);
346
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
347
        $this->assertTrue($co->prepare());
348
        $co->proceed();
349
        $courseid = $DB->get_field('course', 'id', array('shortname' => 'newcourse2'));
350
        $this->assertNotEmpty($courseid);
351
        $this->assertEquals(15 + 1,
352
            $DB->count_records('course_sections', ['course' => $courseid]));
353
    }
354
 
355
    public function test_delete() {
356
        global $DB;
357
        $this->initialise_test();
358
 
359
        $c1 = $this->getDataGenerator()->create_course();
360
        $c2 = $this->getDataGenerator()->create_course();
361
 
362
        $this->assertTrue($DB->record_exists('course', array('shortname' => $c1->shortname)));
363
        $this->assertFalse($DB->record_exists('course', array('shortname' => 'DoesNotExist')));
364
 
365
        $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
366
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
367
 
368
        // Try delete when option not available.
369
        $importoptions = array('candelete' => false);
370
        $data = array('shortname' => $c1->shortname, 'delete' => 1);
371
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
372
        $this->assertFalse($co->prepare());
373
        $this->assertArrayHasKey('coursedeletionnotallowed', $co->get_errors());
374
        $this->assertTrue($DB->record_exists('course', array('shortname' => $c1->shortname)));
375
 
376
        // Try delete when not requested.
377
        $importoptions = array('candelete' => true);
378
        $data = array('shortname' => $c1->shortname, 'delete' => 0);
379
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
380
        $this->assertTrue($co->prepare());
381
        $co->proceed();
382
        $this->assertTrue($DB->record_exists('course', array('shortname' => $c1->shortname)));
383
 
384
        // Try delete when requested.
385
        $importoptions = array('candelete' => true);
386
        $data = array('shortname' => $c1->shortname, 'delete' => 1);
387
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
388
        $this->assertTrue($co->prepare());
389
        $co->proceed();
390
        $this->assertFalse($DB->record_exists('course', array('shortname' => $c1->shortname)));
391
        $this->assertTrue($DB->record_exists('course', array('shortname' => $c2->shortname)));
392
 
393
        // Try deleting non-existing record, this should not fail.
394
        $data = array('shortname' => 'DoesNotExist', 'delete' => 1);
395
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
396
        $this->assertFalse($co->prepare());
397
        $this->assertArrayHasKey('cannotdeletecoursenotexist', $co->get_errors());
398
    }
399
 
400
    public function test_update() {
401
        global $DB;
402
        $this->initialise_test();
403
 
404
        $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1'));
405
 
406
        // Try to update with existing shortnames, not allowing creation, and updating nothing.
407
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
408
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
409
        $data = array('shortname' => 'c1', 'fullname' => 'New fullname');
410
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
411
        $this->assertFalse($co->prepare());
412
        $this->assertArrayHasKey('updatemodedoessettonothing', $co->get_errors());
413
 
414
        // Try to update with non-existing shortnames.
415
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
416
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
417
        $data = array('shortname' => 'DoesNotExist', 'fullname' => 'New fullname');
418
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
419
        $this->assertFalse($co->prepare());
420
        $this->assertArrayHasKey('coursedoesnotexistandcreatenotallowed', $co->get_errors());
421
 
422
        // Try a proper update.
423
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
424
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
425
        $data = array('shortname' => 'c1', 'fullname' => 'New fullname');
426
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
427
        $this->assertTrue($co->prepare());
428
        $co->proceed();
429
        $this->assertEquals('New fullname', $DB->get_field_select('course', 'fullname', 'shortname = :s', array('s' => 'c1')));
430
 
431
        // Try a proper update with defaults.
432
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
433
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS;
434
        $data = array('shortname' => 'c1', 'fullname' => 'Another fullname');
435
        $defaults = array('fullname' => 'Not this one', 'summary' => 'Awesome summary');
436
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults);
437
        $this->assertTrue($co->prepare());
438
        $co->proceed();
439
        $this->assertEquals('Another fullname', $DB->get_field_select('course', 'fullname', 'shortname = :s', array('s' => 'c1')));
440
        $this->assertEquals('Awesome summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
441
 
442
        // Try a proper update missing only.
443
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
444
        $updatemode = tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS;
445
        $DB->set_field('course', 'summary', '', array('shortname' => 'c1'));
446
        $this->assertEquals('', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
447
        $data = array('shortname' => 'c1', 'summary' => 'Fill in summary');
448
        $defaults = array('summary' => 'Do not use this summary');
449
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults);
450
        $this->assertTrue($co->prepare());
451
        $co->proceed();
452
        $this->assertEquals('Fill in summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
453
 
454
        // Try a proper update missing only using defaults.
455
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
456
        $updatemode = tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS;
457
        $DB->set_field('course', 'summary', '', array('shortname' => 'c1'));
458
        $this->assertEquals('', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
459
        $data = array('shortname' => 'c1');
460
        $defaults = array('summary' => 'Use this summary');
461
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults);
462
        $this->assertTrue($co->prepare());
463
        $co->proceed();
464
        $this->assertEquals('Use this summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
465
 
466
        // Update course format option.
467
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
468
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
469
        $data = array('shortname' => 'c1', 'coursedisplay' => 1);
470
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
471
        $this->assertTrue($co->prepare());
472
        $co->proceed();
473
        $course = $DB->get_record('course', array('shortname' => 'c1'), '*', MUST_EXIST);
474
        $this->assertEquals(1, course_get_format($course)->get_course()->coursedisplay);
475
    }
476
 
477
    public function test_data_saved() {
478
        global $DB;
479
 
480
        $this->initialise_test();
481
 
482
        set_config('downloadcoursecontentallowed', 1);
483
 
484
        // Create.
485
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
486
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
487
        $data = array(
488
            'shortname' => 'c1',
489
            'fullname' => 'Fullname',
490
            'category' => '1',
491
            'visible' => '0',
492
            'downloadcontent' => DOWNLOAD_COURSE_CONTENT_DISABLED,
493
            'idnumber' => '123abc',
494
            'summary' => 'Summary',
495
            'format' => 'topics',
496
            'theme' => 'afterburner',
497
            'lang' => 'en',
498
            'newsitems' => '7',
499
            'showgrades' => '0',
500
            'showreports' => '1',
501
            'legacyfiles' => '1',
502
            'maxbytes' => '1234',
503
            'groupmode' => '2',
504
            'groupmodeforce' => '1',
505
            'enablecompletion' => '1',
506
            'showactivitydates' => '1',
507
            'tags' => 'Cat, Dog',
508
 
509
            'role_teacher' => 'Knight',
510
            'role_manager' => 'Jedi',
511
 
512
            'enrolment_1' => 'guest',
513
            'enrolment_2' => 'self',
514
            'enrolment_2_roleid' => '1',
515
            'enrolment_3' => 'manual',
516
            'enrolment_3_disable' => '1',
517
        );
518
 
519
        // There should be a start date if there is a end date.
520
        $data['enddate'] = '7 June 1990';
521
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
522
        $this->assertFalse($co->prepare());
523
        $this->assertArrayHasKey('nostartdatenoenddate', $co->get_errors());
524
 
525
        $data['startdate'] = '8 June 1990';
526
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
527
        $this->assertFalse($co->prepare());
528
        $this->assertArrayHasKey('enddatebeforestartdate', $co->get_errors());
529
 
530
        // They are correct now.
531
        $data['enddate'] = '18 June 1990';
532
 
533
        $this->assertFalse($DB->record_exists('course', array('shortname' => 'c1')));
534
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
535
        $this->assertTrue($co->prepare());
536
        $co->proceed();
537
        $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
538
        $course = $DB->get_record('course', array('shortname' => 'c1'));
539
        $ctx = \context_course::instance($course->id);
540
 
541
        $this->assertEquals($data['fullname'], $course->fullname);
542
        $this->assertEquals($data['category'], $course->category);
543
        $this->assertEquals($data['visible'], $course->visible);
544
        $this->assertEquals($data['downloadcontent'], $course->downloadcontent);
545
        $this->assertEquals(mktime(0, 0, 0, 6, 8, 1990), $course->startdate);
546
        $this->assertEquals(mktime(0, 0, 0, 6, 18, 1990), $course->enddate);
547
        $this->assertEquals($data['idnumber'], $course->idnumber);
548
        $this->assertEquals($data['summary'], $course->summary);
549
        $this->assertEquals($data['format'], $course->format);
550
        $this->assertEquals($data['theme'], $course->theme);
551
        $this->assertEquals($data['lang'], $course->lang);
552
        $this->assertEquals($data['newsitems'], $course->newsitems);
553
        $this->assertEquals($data['showgrades'], $course->showgrades);
554
        $this->assertEquals($data['showreports'], $course->showreports);
555
        $this->assertEquals($data['legacyfiles'], $course->legacyfiles);
556
        $this->assertEquals($data['maxbytes'], $course->maxbytes);
557
        $this->assertEquals($data['groupmode'], $course->groupmode);
558
        $this->assertEquals($data['groupmodeforce'], $course->groupmodeforce);
559
        $this->assertEquals($data['enablecompletion'], $course->enablecompletion);
560
        $this->assertEquals($data['showactivitydates'], $course->showactivitydates);
561
        $this->assertEquals($data['tags'], join(', ', \core_tag_tag::get_item_tags_array('core', 'course', $course->id)));
562
 
563
        // Roles.
564
        $roleids = array();
565
        $roles = get_all_roles();
566
        foreach ($roles as $role) {
567
            $roleids[$role->shortname] = $role->id;
568
        }
569
        $this->assertEquals('Knight', $DB->get_field_select('role_names', 'name',
570
            'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['teacher'])));
571
        $this->assertEquals('Jedi', $DB->get_field_select('role_names', 'name',
572
            'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['manager'])));
573
 
574
        // Enrolment methods.
575
        $enroldata = array();
576
        $instances = enrol_get_instances($course->id, false);
577
        $this->assertCount(3, $instances);
578
        foreach ($instances as $instance) {
579
            $enroldata[$instance->enrol] = $instance;
580
        }
581
 
582
        $this->assertNotEmpty($enroldata['guest']);
583
        $this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['guest']->status);
584
        $this->assertNotEmpty($enroldata['self']);
585
        $this->assertEquals($data['enrolment_2_roleid'], $enroldata['self']->roleid);
586
        $this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['self']->status);
587
        $this->assertNotEmpty($enroldata['manual']);
588
        $this->assertEquals(ENROL_INSTANCE_DISABLED, $enroldata['manual']->status);
589
 
590
        // Update existing course.
591
        $cat = $this->getDataGenerator()->create_category();
592
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
593
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
594
        $data = array(
595
            'shortname' => 'c1',
596
            'fullname' => 'Fullname 2',
597
            'category' => $cat->id,
598
            'visible' => '1',
599
            'downloadcontent' => DOWNLOAD_COURSE_CONTENT_ENABLED,
600
            'idnumber' => 'changeidn',
601
            'summary' => 'Summary 2',
602
            'format' => 'topics',
603
            'theme' => 'classic',
604
            'lang' => '',
605
            'newsitems' => '2',
606
            'showgrades' => '1',
607
            'showreports' => '0',
608
            'legacyfiles' => '0',
609
            'maxbytes' => '4321',
610
            'groupmode' => '1',
611
            'groupmodeforce' => '0',
612
            'enablecompletion' => '0',
613
            'showactivitydates' => '0',
614
 
615
            'role_teacher' => 'Teacher',
616
            'role_manager' => 'Manager',
617
 
618
            'enrolment_1' => 'guest',
619
            'enrolment_1_disable' => '1',
620
            'enrolment_2' => 'self',
621
            'enrolment_2_roleid' => '5',
622
            'enrolment_3' => 'manual',
623
            'enrolment_3_delete' => '1',
624
        );
625
 
626
        $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
627
 
628
        $data['enddate'] = '31 June 1984';
629
        // Previous start and end dates are 8 and 18 June 1990.
630
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
631
        $this->assertFalse($co->prepare());
632
        $this->assertArrayHasKey('enddatebeforestartdate', $co->get_errors());
633
 
634
        $data['startdate'] = '19 June 1990';
635
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
636
        $this->assertFalse($co->prepare());
637
        $this->assertArrayHasKey('enddatebeforestartdate', $co->get_errors());
638
 
639
        // They are correct now.
640
        $data['startdate'] = '11 June 1984';
641
 
642
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
643
        $this->assertTrue($co->prepare());
644
        $co->proceed();
645
        $course = $DB->get_record('course', array('shortname' => 'c1'));
646
        $ctx = \context_course::instance($course->id);
647
 
648
        $this->assertEquals($data['fullname'], $course->fullname);
649
        $this->assertEquals($data['category'], $course->category);
650
        $this->assertEquals($data['visible'], $course->visible);
651
        $this->assertEquals($data['downloadcontent'], $course->downloadcontent);
652
        $this->assertEquals(mktime(0, 0, 0, 6, 11, 1984), $course->startdate);
653
        $this->assertEquals(mktime(0, 0, 0, 6, 31, 1984), $course->enddate);
654
        $this->assertEquals($data['idnumber'], $course->idnumber);
655
        $this->assertEquals($data['summary'], $course->summary);
656
        $this->assertEquals($data['format'], $course->format);
657
        $this->assertEquals($data['theme'], $course->theme);
658
        $this->assertEquals($data['lang'], $course->lang);
659
        $this->assertEquals($data['newsitems'], $course->newsitems);
660
        $this->assertEquals($data['showgrades'], $course->showgrades);
661
        $this->assertEquals($data['showreports'], $course->showreports);
662
        $this->assertEquals($data['legacyfiles'], $course->legacyfiles);
663
        $this->assertEquals($data['maxbytes'], $course->maxbytes);
664
        $this->assertEquals($data['groupmode'], $course->groupmode);
665
        $this->assertEquals($data['groupmodeforce'], $course->groupmodeforce);
666
        $this->assertEquals($data['enablecompletion'], $course->enablecompletion);
667
        $this->assertEquals($data['showactivitydates'], $course->showactivitydates);
668
 
669
        // Roles.
670
        $roleids = array();
671
        $roles = get_all_roles();
672
        foreach ($roles as $role) {
673
            $roleids[$role->shortname] = $role->id;
674
        }
675
        $this->assertEquals('Teacher', $DB->get_field_select('role_names', 'name',
676
            'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['teacher'])));
677
        $this->assertEquals('Manager', $DB->get_field_select('role_names', 'name',
678
            'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['manager'])));
679
 
680
        // Enrolment methods.
681
        $enroldata = array();
682
        $instances = enrol_get_instances($course->id, false);
683
        $this->assertCount(2, $instances);
684
        foreach ($instances as $instance) {
685
            $enroldata[$instance->enrol] = $instance;
686
        }
687
 
688
        $this->assertNotEmpty($enroldata['guest']);
689
        $this->assertEquals(ENROL_INSTANCE_DISABLED, $enroldata['guest']->status);
690
        $this->assertNotEmpty($enroldata['self']);
691
        $this->assertEquals($data['enrolment_2_roleid'], $enroldata['self']->roleid);
692
        $this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['self']->status);
693
    }
694
 
695
    public function test_default_data_saved() {
696
        global $DB;
697
 
698
        $this->initialise_test();
699
 
700
        set_config('downloadcoursecontentallowed', 1);
701
 
702
        // Create.
703
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
704
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
705
        $data = array(
706
            'shortname' => 'c1',
707
        );
708
        $defaultdata = array(
709
            'fullname' => 'Fullname',
710
            'category' => '1',
711
            'visible' => '0',
712
            'downloadcontent' => DOWNLOAD_COURSE_CONTENT_DISABLED,
713
            'startdate' => 644803200,
714
            'enddate' => 645667200,
715
            'idnumber' => '123abc',
716
            'summary' => 'Summary',
717
            'format' => 'topics',
718
            'theme' => 'afterburner',
719
            'lang' => 'en',
720
            'newsitems' => '7',
721
            'showgrades' => '0',
722
            'showreports' => '1',
723
            'legacyfiles' => '1',
724
            'maxbytes' => '1234',
725
            'groupmode' => '2',
726
            'groupmodeforce' => '1',
727
            'enablecompletion' => '1',
728
            'showactivitydates' => '1',
729
        );
730
 
731
        $this->assertFalse($DB->record_exists('course', array('shortname' => 'c1')));
732
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaultdata);
733
        $this->assertTrue($co->prepare());
734
        $co->proceed();
735
        $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
736
        $course = $DB->get_record('course', array('shortname' => 'c1'));
737
        $ctx = \context_course::instance($course->id);
738
 
739
        $this->assertEquals($defaultdata['fullname'], $course->fullname);
740
        $this->assertEquals($defaultdata['category'], $course->category);
741
        $this->assertEquals($defaultdata['visible'], $course->visible);
742
        $this->assertEquals($defaultdata['downloadcontent'], $course->downloadcontent);
743
        $this->assertEquals($defaultdata['startdate'], $course->startdate);
744
        $this->assertEquals($defaultdata['enddate'], $course->enddate);
745
        $this->assertEquals($defaultdata['idnumber'], $course->idnumber);
746
        $this->assertEquals($defaultdata['summary'], $course->summary);
747
        $this->assertEquals($defaultdata['format'], $course->format);
748
        $this->assertEquals($defaultdata['theme'], $course->theme);
749
        $this->assertEquals($defaultdata['lang'], $course->lang);
750
        $this->assertEquals($defaultdata['newsitems'], $course->newsitems);
751
        $this->assertEquals($defaultdata['showgrades'], $course->showgrades);
752
        $this->assertEquals($defaultdata['showreports'], $course->showreports);
753
        $this->assertEquals($defaultdata['legacyfiles'], $course->legacyfiles);
754
        $this->assertEquals($defaultdata['maxbytes'], $course->maxbytes);
755
        $this->assertEquals($defaultdata['groupmode'], $course->groupmode);
756
        $this->assertEquals($defaultdata['groupmodeforce'], $course->groupmodeforce);
757
        $this->assertEquals($defaultdata['enablecompletion'], $course->enablecompletion);
758
        $this->assertEquals($defaultdata['showactivitydates'], $course->showactivitydates);
759
 
760
        // Update.
761
        $cat = $this->getDataGenerator()->create_category();
762
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
763
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS;
764
        $data = array(
765
            'shortname' => 'c1',
766
        );
767
        $defaultdata = array(
768
            'fullname' => 'Fullname 2',
769
            'category' => $cat->id,
770
            'visible' => '1',
771
            'downloadcontent' => DOWNLOAD_COURSE_CONTENT_ENABLED,
772
            'startdate' => 455760000,
773
            'enddate' => 457488000,
774
            'idnumber' => 'changedid',
775
            'summary' => 'Summary 2',
776
            'format' => 'topics',
777
            'theme' => 'classic',
778
            'lang' => '',
779
            'newsitems' => '2',
780
            'showgrades' => '1',
781
            'showreports' => '0',
782
            'legacyfiles' => '0',
783
            'maxbytes' => '1111',
784
            'groupmode' => '1',
785
            'groupmodeforce' => '0',
786
            'enablecompletion' => '0',
787
            'showactivitydates' => '0',
788
        );
789
 
790
        $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
791
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaultdata);
792
        $this->assertTrue($co->prepare());
793
        $co->proceed();
794
        $this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
795
        $course = $DB->get_record('course', array('shortname' => 'c1'));
796
        $ctx = \context_course::instance($course->id);
797
 
798
        $this->assertEquals($defaultdata['fullname'], $course->fullname);
799
        $this->assertEquals($defaultdata['category'], $course->category);
800
        $this->assertEquals($defaultdata['visible'], $course->visible);
801
        $this->assertEquals($defaultdata['downloadcontent'], $course->downloadcontent);
802
        $this->assertEquals($defaultdata['startdate'], $course->startdate);
803
        $this->assertEquals($defaultdata['enddate'], $course->enddate);
804
        $this->assertEquals($defaultdata['idnumber'], $course->idnumber);
805
        $this->assertEquals($defaultdata['summary'], $course->summary);
806
        $this->assertEquals($defaultdata['format'], $course->format);
807
        $this->assertEquals($defaultdata['theme'], $course->theme);
808
        $this->assertEquals($defaultdata['lang'], $course->lang);
809
        $this->assertEquals($defaultdata['newsitems'], $course->newsitems);
810
        $this->assertEquals($defaultdata['showgrades'], $course->showgrades);
811
        $this->assertEquals($defaultdata['showreports'], $course->showreports);
812
        $this->assertEquals($defaultdata['legacyfiles'], $course->legacyfiles);
813
        $this->assertEquals($defaultdata['maxbytes'], $course->maxbytes);
814
        $this->assertEquals($defaultdata['groupmode'], $course->groupmode);
815
        $this->assertEquals($defaultdata['groupmodeforce'], $course->groupmodeforce);
816
        $this->assertEquals($defaultdata['enablecompletion'], $course->enablecompletion);
817
        $this->assertEquals($defaultdata['showactivitydates'], $course->showactivitydates);
818
    }
819
 
820
    public function test_rename() {
821
        global $DB;
822
        $this->initialise_test();
823
 
824
        $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1'));
825
        $c2 = $this->getDataGenerator()->create_course(array('shortname' => 'c2'));
826
 
827
        // Cannot rename when creating.
828
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
829
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
830
        $importoptions = array('canrename' => true);
831
        $data = array('shortname' => 'c1', 'rename' => 'newshortname');
832
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
833
        $this->assertFalse($co->prepare());
834
        $this->assertArrayHasKey('courseexistsanduploadnotallowed', $co->get_errors());
835
 
836
        // Cannot rename when creating.
837
        $mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
838
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
839
        $importoptions = array('canrename' => true);
840
        $data = array('shortname' => 'c1', 'rename' => 'newshortname', 'category' => 1, 'summary' => 'S', 'fullname' => 'F');
841
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
842
        $this->assertFalse($co->prepare());
843
        $this->assertArrayHasKey('canonlyrenameinupdatemode', $co->get_errors());
844
 
845
        // Error when not allowed to rename the course.
846
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
847
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
848
        $importoptions = array('canrename' => false);
849
        $data = array('shortname' => 'c1', 'rename' => 'newshortname');
850
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
851
        $this->assertFalse($co->prepare());
852
        $this->assertArrayHasKey('courserenamingnotallowed', $co->get_errors());
853
 
854
        // Can rename when updating.
855
        $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
856
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
857
        $importoptions = array('canrename' => true);
858
        $data = array('shortname' => 'c1', 'rename' => 'newshortname');
859
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
860
        $this->assertTrue($co->prepare());
861
        $co->proceed();
862
        $this->assertEquals('newshortname', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id)));
863
 
864
        // Can rename when updating.
865
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
866
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
867
        $importoptions = array('canrename' => true);
868
        $data = array('shortname' => 'newshortname', 'rename' => 'newshortname2');
869
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
870
        $this->assertTrue($co->prepare());
871
        $co->proceed();
872
        $this->assertEquals('newshortname2', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id)));
873
 
874
        // Error when course does not exist.
875
        $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
876
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
877
        $importoptions = array('canrename' => true);
878
        $data = array('shortname' => 'DoesNotExist', 'rename' => 'c1', 'category' => 1, 'summary' => 'S', 'fullname' => 'F');
879
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
880
        $this->assertFalse($co->prepare());
881
        $this->assertArrayHasKey('cannotrenamecoursenotexist', $co->get_errors());
882
 
883
        // Renaming still updates the other values.
884
        $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
885
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS;
886
        $importoptions = array('canrename' => true);
887
        $data = array('shortname' => 'newshortname2', 'rename' => 'c1', 'fullname' => 'Another fullname!');
888
        $defaultdata = array('summary' => 'New summary!');
889
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaultdata, $importoptions);
890
        $this->assertTrue($co->prepare());
891
        $co->proceed();
892
        $this->assertEquals('c1', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id)));
893
        $this->assertEquals('New summary!', $DB->get_field_select('course', 'summary', 'id = :id', array('id' => $c1->id)));
894
        $this->assertEquals('Another fullname!', $DB->get_field_select('course', 'fullname', 'id = :id', array('id' => $c1->id)));
895
 
896
        // Renaming with invalid shortname.
897
        $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
898
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
899
        $importoptions = array('canrename' => true);
900
        $data = array('shortname' => 'c1', 'rename' => '<span>invalid</span>');
901
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
902
        $this->assertFalse($co->prepare());
903
        $this->assertArrayHasKey('invalidshortname', $co->get_errors());
904
 
905
        // Renaming with invalid shortname.
906
        $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
907
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
908
        $importoptions = array('canrename' => true);
909
        $data = array('shortname' => 'c1', 'rename' => 'c2');
910
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
911
        $this->assertFalse($co->prepare());
912
        $this->assertArrayHasKey('cannotrenameshortnamealreadyinuse', $co->get_errors());
913
    }
914
 
915
    public function test_restore_course() {
916
        global $DB;
917
        $this->initialise_test();
918
        $this->setAdminUser();
919
 
920
        $c1 = $this->getDataGenerator()->create_course();
921
        $c1f1 = $this->getDataGenerator()->create_module('forum', array('course' => $c1->id));
922
 
923
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
924
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
925
        $data = array('shortname' => 'A1', 'templatecourse' => $c1->shortname, 'summary' => 'A', 'category' => 1,
926
            'fullname' => 'A1');
927
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
928
        $this->assertTrue($co->prepare());
929
        $co->proceed();
930
        $course = $DB->get_record('course', array('shortname' => 'A1'));
931
        $modinfo = get_fast_modinfo($course);
932
        $found = false;
933
        foreach ($modinfo->get_cms() as $cmid => $cm) {
934
            if ($cm->modname == 'forum' && $cm->name == $c1f1->name) {
935
                $found = true;
936
                break;
937
            }
938
        }
939
        $this->assertTrue($found);
940
 
941
        // Restoring twice from the same course should work.
942
        $data = array('shortname' => 'B1', 'templatecourse' => $c1->shortname, 'summary' => 'B', 'category' => 1,
943
            'fullname' => 'B1');
944
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
945
        $this->assertTrue($co->prepare());
946
        $co->proceed();
947
        $course = $DB->get_record('course', array('shortname' => 'B1'));
948
        $modinfo = get_fast_modinfo($course);
949
        $found = false;
950
        foreach ($modinfo->get_cms() as $cmid => $cm) {
951
            if ($cm->modname == 'forum' && $cm->name == $c1f1->name) {
952
                $found = true;
953
                break;
954
            }
955
        }
956
        $this->assertTrue($found);
957
    }
958
 
959
    public function test_restore_file() {
960
        global $DB;
961
        $this->initialise_test();
962
        $this->setAdminUser();
963
 
964
        $c1 = $this->getDataGenerator()->create_course();
965
        $c1f1 = $this->getDataGenerator()->create_module('forum', array('course' => $c1->id));
966
 
967
        // Restore from a file, checking that the file takes priority over the templatecourse.
968
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
969
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
970
        $data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
971
            'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname);
972
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
973
        $this->assertTrue($co->prepare());
974
        $co->proceed();
975
        $course = $DB->get_record('course', array('shortname' => 'A1'));
976
        $modinfo = get_fast_modinfo($course);
977
        $found = false;
978
        foreach ($modinfo->get_cms() as $cmid => $cm) {
979
            if ($cm->modname == 'glossary' && $cm->name == 'Imported Glossary') {
980
                $found = true;
981
            } else if ($cm->modname == 'forum' && $cm->name == $c1f1->name) {
982
                // We should not find this!
983
                $this->assertTrue(false);
984
            }
985
        }
986
        $this->assertTrue($found);
987
 
988
        // Restoring twice from the same file should work.
989
        $data = array('shortname' => 'B1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
990
            'summary' => 'B', 'category' => 1, 'fullname' => 'B1');
991
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
992
        $this->assertTrue($co->prepare());
993
        $co->proceed();
994
        $course = $DB->get_record('course', array('shortname' => 'B1'));
995
        $modinfo = get_fast_modinfo($course);
996
        $found = false;
997
        foreach ($modinfo->get_cms() as $cmid => $cm) {
998
            if ($cm->modname == 'glossary' && $cm->name == 'Imported Glossary') {
999
                $found = true;
1000
            } else if ($cm->modname == 'forum' && $cm->name == $c1f1->name) {
1001
                // We should not find this!
1002
                $this->assertTrue(false);
1003
            }
1004
        }
1005
        $this->assertTrue($found);
1006
    }
1007
 
1008
    /**
1009
     * Test that specifying course template respects default restore settings
1010
     */
1011
    public function test_restore_file_settings() {
1012
        global $DB;
1013
        $this->initialise_test();
1014
        $this->setAdminUser();
1015
 
1016
        // Set admin config setting so that activities are not restored by default.
1017
        set_config('restore_general_activities', 0, 'restore');
1018
 
1019
        $c1 = $this->getDataGenerator()->create_course();
1020
 
1021
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1022
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1023
        $data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
1024
            'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname);
1025
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1026
        $this->assertTrue($co->prepare());
1027
        $co->proceed();
1028
        $course = $DB->get_record('course', array('shortname' => 'A1'));
1029
 
1030
        // Make sure the glossary is not restored.
1031
        $modinfo = get_fast_modinfo($course);
1032
        $this->assertEmpty($modinfo->get_instances_of('glossary'));
1033
    }
1034
 
1035
    public function test_restore_invalid_file() {
1036
        $this->initialise_test();
1037
 
1038
        // Restore from a non-existing file should not be allowed.
1039
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1040
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1041
        $data = array('shortname' => 'A1', 'backupfile' => '/lead/no/where',
1042
            'category' => 1, 'fullname' => 'A1');
1043
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1044
        $this->assertFalse($co->prepare());
1045
        $this->assertArrayHasKey('cannotreadbackupfile', $co->get_errors());
1046
 
1047
        // Restore from an invalid file should not be allowed.
1048
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1049
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1050
        $data = array('shortname' => 'A1', 'backupfile' => __FILE__,
1051
            'category' => 1, 'fullname' => 'A1');
1052
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1053
 
1054
        $this->assertFalse($co->prepare());
1055
        $this->assertArrayHasKey('invalidbackupfile', $co->get_errors());
1056
 
1057
        // Zip packer throws a debugging message, this assertion is only here to prevent
1058
        // the message from being displayed.
1059
        $this->assertDebuggingCalled();
1060
    }
1061
 
1062
    public function test_restore_invalid_course() {
1063
        $this->initialise_test();
1064
 
1065
        // Restore from an invalid file should not be allowed.
1066
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1067
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1068
        $data = array('shortname' => 'A1', 'templatecourse' => 'iamnotavalidcourse',
1069
            'category' => 1, 'fullname' => 'A1');
1070
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1071
        $this->assertFalse($co->prepare());
1072
        $this->assertArrayHasKey('coursetorestorefromdoesnotexist', $co->get_errors());
1073
    }
1074
 
1075
    /**
1076
     * Testing the reset on groups, group members and enrolments.
1077
     */
1078
    public function test_reset() {
1079
        global $DB;
1080
        $this->initialise_test();
1081
 
1082
        $c1 = $this->getDataGenerator()->create_course();
1083
        $c1ctx = \context_course::instance($c1->id);
1084
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1085
        $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1086
 
1087
        $u1 = $this->getDataGenerator()->create_user();
1088
        $this->getDataGenerator()->enrol_user($u1->id, $c1->id, $studentrole->id);
1089
        $this->assertCount(1, get_enrolled_users($c1ctx));
1090
 
1091
        $g1 = $this->getDataGenerator()->create_group(array('courseid' => $c1->id));
1092
        $this->getDataGenerator()->create_group_member(array('groupid' => $g1->id, 'userid' => $u1->id));
1093
        $this->assertEquals(1, $DB->count_records('groups', array('courseid' => $c1->id)));
1094
        $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
1095
 
1096
        // Wrong mode.
1097
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1098
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1099
        $data = array('shortname' => 'DoesNotExist', 'reset' => '1', 'summary' => 'summary', 'fullname' => 'FN', 'category' => 1);
1100
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1101
        $this->assertFalse($co->prepare());
1102
        $this->assertArrayHasKey('canonlyresetcourseinupdatemode', $co->get_errors());
1103
        $this->assertTrue($DB->record_exists('groups', array('id' => $g1->id)));
1104
        $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
1105
        $this->assertCount(1, get_enrolled_users($c1ctx));
1106
 
1107
        // Reset not allowed.
1108
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1109
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1110
        $data = array('shortname' => $c1->shortname, 'reset' => '1');
1111
        $importoptions = array('canreset' => false);
1112
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1113
        $this->assertFalse($co->prepare());
1114
        $this->assertArrayHasKey('courseresetnotallowed', $co->get_errors());
1115
        $this->assertTrue($DB->record_exists('groups', array('id' => $g1->id)));
1116
        $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
1117
        $this->assertCount(1, get_enrolled_users($c1ctx));
1118
 
1119
        // Reset allowed but not requested.
1120
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1121
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1122
        $data = array('shortname' => $c1->shortname, 'reset' => '0');
1123
        $importoptions = array('canreset' => true);
1124
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1125
        $this->assertTrue($co->prepare());
1126
        $co->proceed();
1127
        $this->assertTrue($DB->record_exists('groups', array('id' => $g1->id)));
1128
        $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
1129
        $this->assertCount(1, get_enrolled_users($c1ctx));
1130
 
1131
        // Reset passed as a default parameter, should not be taken in account.
1132
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1133
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1134
        $data = array('shortname' => $c1->shortname);
1135
        $importoptions = array('canreset' => true);
1136
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array('reset' => 1), $importoptions);
1137
        $this->assertTrue($co->prepare());
1138
        $co->proceed();
1139
        $this->assertTrue($DB->record_exists('groups', array('id' => $g1->id)));
1140
        $this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
1141
        $this->assertCount(1, get_enrolled_users($c1ctx));
1142
 
1143
        // Reset executed from data.
1144
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1145
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1146
        $data = array('shortname' => $c1->shortname, 'reset' => 1);
1147
        $importoptions = array('canreset' => true);
1148
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1149
        $this->assertTrue($co->prepare());
1150
        $co->proceed();
1151
        $this->assertFalse($DB->record_exists('groups', array('id' => $g1->id)));
1152
        $this->assertFalse($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
1153
        $this->assertCount(0, get_enrolled_users($c1ctx));
1154
 
1155
        // Reset executed from import option.
1156
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1157
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1158
        $data = array('shortname' => $c1->shortname, 'reset' => 0);
1159
        $importoptions = array('reset' => 1, 'canreset' => true);
1160
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1161
 
1162
        $g1 = $this->getDataGenerator()->create_group(array('courseid' => $c1->id));
1163
        $this->getDataGenerator()->create_group_member(array('groupid' => $g1->id, 'userid' => $u1->id));
1164
        $this->assertEquals(1, $DB->count_records('groups', array('courseid' => $c1->id)));
1165
        $this->assertTrue($co->prepare());
1166
        $co->proceed();
1167
        $this->assertFalse($DB->record_exists('groups', array('id' => $g1->id)));
1168
    }
1169
 
1170
    public function test_create_bad_category() {
1171
        global $DB;
1172
        $this->initialise_test();
1173
 
1174
        // Ensure fails when category cannot be resolved upon creation.
1175
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1176
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1177
        $data = array('shortname' => 'c1', 'summary' => 'summary', 'fullname' => 'FN', 'category' => 'Wrong cat');
1178
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1179
        $this->assertFalse($co->prepare());
1180
        $this->assertArrayHasKey('couldnotresolvecatgorybyid', $co->get_errors());
1181
 
1182
        // Ensure fails when category is 0 on create.
1183
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1184
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1185
        $data = array('shortname' => 'c1', 'summary' => 'summary', 'fullname' => 'FN', 'category' => '0');
1186
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1187
        $this->assertFalse($co->prepare());
1188
        $this->assertArrayHasKey('missingmandatoryfields', $co->get_errors());
1189
 
1190
        // Ensure fails when category cannot be resolved upon update.
1191
        $c1 = $this->getDataGenerator()->create_course();
1192
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1193
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1194
        $data = array('shortname' => $c1->shortname, 'category' => 'Wrong cat');
1195
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1196
        $this->assertFalse($co->prepare());
1197
        $this->assertArrayHasKey('couldnotresolvecatgorybyid', $co->get_errors());
1198
 
1199
        // Ensure does not update the category when it is 0.
1200
        $c1 = $this->getDataGenerator()->create_course();
1201
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1202
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1203
        $data = array('shortname' => $c1->shortname, 'category' => '0');
1204
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1205
        $this->assertTrue($co->prepare());
1206
        $this->assertEmpty($co->get_errors());
1207
        $this->assertEmpty($co->get_statuses());
1208
        $co->proceed();
1209
        $this->assertEquals($c1->category, $DB->get_field('course', 'category', array('id' => $c1->id)));
1210
 
1211
        // Ensure does not update the category when it is set to 0 in the defaults.
1212
        $c1 = $this->getDataGenerator()->create_course();
1213
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1214
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS;
1215
        $data = array('shortname' => $c1->shortname);
1216
        $defaults = array('category' => '0');
1217
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults);
1218
        $this->assertTrue($co->prepare());
1219
        $this->assertEmpty($co->get_errors());
1220
        $this->assertEmpty($co->get_statuses());
1221
        $co->proceed();
1222
        $this->assertEquals($c1->category, $DB->get_field('course', 'category', array('id' => $c1->id)));
1223
    }
1224
 
1225
    public function test_enrolment_data() {
1226
        $this->initialise_test();
1227
 
1228
        // We need to set the current user as one with the capability to edit manual enrolment instances in the new course.
1229
        $this->setAdminUser();
1230
 
1231
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1232
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1233
        $data = array('shortname' => 'c1', 'summary' => 'S', 'fullname' => 'FN', 'category' => '1');
1234
        $data['enrolment_1'] = 'manual';
1235
        $data['enrolment_1_role'] = 'teacher';
1236
        $data['enrolment_1_startdate'] = '2nd July 2013';
1237
        $data['enrolment_1_enddate'] = '2nd August 2013';
1238
        $data['enrolment_1_enrolperiod'] = '10 days';
1239
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1240
        $this->assertTrue($co->prepare());
1241
        $co->proceed();
1242
 
1243
        // Enrolment methods.
1244
        $enroldata = array();
1245
        $instances = enrol_get_instances($co->get_id(), false);
1246
        foreach ($instances as $instance) {
1247
            $enroldata[$instance->enrol] = $instance;
1248
        }
1249
 
1250
        $this->assertNotEmpty($enroldata['manual']);
1251
        $this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['manual']->status);
1252
        $this->assertEquals(strtotime($data['enrolment_1_startdate']), $enroldata['manual']->enrolstartdate);
1253
        $this->assertEquals(strtotime('1970-01-01 GMT + ' . $data['enrolment_1_enrolperiod']), $enroldata['manual']->enrolperiod);
1254
        $this->assertEquals(strtotime('12th July 2013'), $enroldata['manual']->enrolenddate);
1255
    }
1256
 
1257
    /**
1258
     * Data provider for testing enrolment errors
1259
     *
1260
     * @return array
1261
     */
1262
    public function enrolment_uploaddata_error_provider(): array {
1263
        return [
1264
            ['errorcannotcreateorupdateenrolment', [
1265
                'shortname' => 'C1',
1266
                'enrolment_1' => 'manual',
1267
            ]],
1268
            ['errorcannotdeleteenrolment', [
1269
                'shortname' => 'C1',
1270
                'enrolment_1' => 'manual',
1271
                'enrolment_1_delete' => '1',
1272
            ]],
1273
            ['errorcannotdisableenrolment', [
1274
                'shortname' => 'C1',
1275
                'enrolment_1' => 'manual',
1276
                'enrolment_1_disable' => '1',
1277
            ]],
1278
        ];
1279
    }
1280
 
1281
    /**
1282
     * Test that user without permission, cannot modify enrolment instances when creating courses
1283
     *
1284
     * @param string $expectederror
1285
     * @param array $uploaddata
1286
     *
1287
     * @dataProvider enrolment_uploaddata_error_provider
1288
     */
1289
    public function test_enrolment_error_create_course(string $expectederror, array $uploaddata): void {
1290
        global $DB;
1291
 
1292
        $this->resetAfterTest();
1293
 
1294
        // Create category in which to create the new course.
1295
        $category = $this->getDataGenerator()->create_category();
1296
        $categorycontext = \context_coursecat::instance($category->id);
1297
 
1298
        $user = $this->getDataGenerator()->create_user();
1299
        $this->setUser($user);
1300
 
1301
        // Assign the user as a manager of the category, disable ability to configure manual enrolment instances.
1302
        $roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
1303
        role_assign($roleid, $user->id, $categorycontext);
1304
        role_change_permission($roleid, $categorycontext, 'enrol/manual:config', CAP_PROHIBIT);
1305
 
1306
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1307
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1308
 
1309
        $upload = new tool_uploadcourse_course($mode, $updatemode, array_merge($uploaddata, [
1310
            'category' => $category->id,
1311
            'fullname' => 'My course',
1312
        ]));
1313
 
1314
        // Enrolment validation isn't performed during 'prepare' for new courses.
1315
        $this->assertTrue($upload->prepare());
1316
        $upload->proceed();
1317
 
1318
        $errors = $upload->get_errors();
1319
        $this->assertArrayHasKey($expectederror, $errors);
1320
 
1321
        $this->assertEquals(get_string($expectederror, 'tool_uploadcourse', 'Manual enrolments'),
1322
            (string) $errors[$expectederror]);
1323
    }
1324
 
1325
    /**
1326
     * Test that user without permission, cannot modify enrolment instances when updating courses
1327
     *
1328
     * @param string $expectederror
1329
     * @param array $uploaddata
1330
     *
1331
     * @dataProvider enrolment_uploaddata_error_provider
1332
     */
1333
    public function test_enrolment_error_update_course(string $expectederror, array $uploaddata): void {
1334
        global $DB;
1335
 
1336
        $this->resetAfterTest();
1337
 
1338
        // Create category in which to create the new course.
1339
        $category = $this->getDataGenerator()->create_category();
1340
        $categorycontext = \context_coursecat::instance($category->id);
1341
 
1342
        $course = $this->getDataGenerator()->create_course([
1343
            'category' => $category->id,
1344
            'shortname' => $uploaddata['shortname'],
1345
        ]);
1346
 
1347
        $user = $this->getDataGenerator()->create_user();
1348
        $this->setUser($user);
1349
 
1350
        // Assign the user as a manager of the category, disable ability to configure manual enrolment instances.
1351
        $roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
1352
        role_assign($roleid, $user->id, $categorycontext);
1353
        role_change_permission($roleid, $categorycontext, 'enrol/manual:config', CAP_PROHIBIT);
1354
 
1355
        // Sanity check.
1356
        $instances = enrol_get_instances($course->id, true);
1357
        $this->assertCount(1, $instances);
1358
        $this->assertEquals('manual', reset($instances)->enrol);
1359
 
1360
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1361
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1362
 
1363
        $upload = new tool_uploadcourse_course($mode, $updatemode, $uploaddata);
1364
 
1365
        $this->assertFalse($upload->prepare());
1366
 
1367
        $errors = $upload->get_errors();
1368
        $this->assertArrayHasKey($expectederror, $errors);
1369
 
1370
        $this->assertEquals(get_string($expectederror, 'tool_uploadcourse', 'Manual enrolments'),
1371
            (string) $errors[$expectederror]);
1372
    }
1373
 
1374
    /**
1375
     * Test upload processing of course custom fields
1376
     */
1377
    public function test_custom_fields_data() {
1378
        $this->resetAfterTest();
1379
        $this->setAdminUser();
1380
 
1381
        $course = $this->getDataGenerator()->create_course(['shortname' => 'C1']);
1382
 
1383
        // Create our custom fields.
1384
        $category = $this->get_customfield_generator()->create_category();
1385
        $this->create_custom_field($category, 'date', 'mydatefield');
1386
        $this->create_custom_field($category, 'text', 'mytextfield');
1387
        $this->create_custom_field($category, 'textarea', 'mytextareafield');
1388
 
1389
        // Perform upload.
1390
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1391
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1392
        $dataupload = [
1393
            'shortname' => $course->shortname,
1394
            'customfield_mydatefield' => '2020-04-01 16:00',
1395
            'customfield_mytextfield' => 'Hello',
1396
            'customfield_mytextareafield' => 'Is it me you\'re looking for?',
1397
        ];
1398
 
1399
        $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload);
1400
        $this->assertTrue($uploader->prepare());
1401
        $uploader->proceed();
1402
 
1403
        // Confirm presence of course custom fields.
1404
        $data = \core_course\customfield\course_handler::create()->export_instance_data_object($course->id);
1405
        $this->assertEqualsIgnoringCase('Wednesday, 1 April 2020, 4:00 PM', $data->mydatefield);
1406
        $this->assertEquals($dataupload['customfield_mytextfield'], $data->mytextfield);
1407
        $this->assertStringContainsString($dataupload['customfield_mytextareafield'], $data->mytextareafield);
1408
    }
1409
 
1410
    /**
1411
     * Test upload processing of course custom field that is required but empty
1412
     */
1413
    public function test_custom_fields_data_required() {
1414
        $this->resetAfterTest();
1415
        $this->setAdminUser();
1416
 
1417
        $course = $this->getDataGenerator()->create_course(['shortname' => 'C1']);
1418
 
1419
        // Create our custom field.
1420
        $category = $this->get_customfield_generator()->create_category();
1421
        $this->create_custom_field($category, 'select', 'myselect', ['required' => true, 'options' => "Cat\nDog"]);
1422
 
1423
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1424
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1425
        $dataupload = [
1426
            'shortname' => $course->shortname,
1427
            'customfield_myselect' => null,
1428
        ];
1429
 
1430
        $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload);
1431
        $this->assertFalse($uploader->prepare());
1432
        $this->assertArrayHasKey('customfieldinvalid', $uploader->get_errors());
1433
 
1434
        // Try again with a default value.
1435
        $defaults = [
1436
            'customfield_myselect' => 2, // Our second option: Dog.
1437
        ];
1438
 
1439
        $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload, $defaults);
1440
        $this->assertTrue($uploader->prepare());
1441
        $uploader->proceed();
1442
 
1443
        // Confirm presence of course custom fields.
1444
        $data = \core_course\customfield\course_handler::create()->export_instance_data_object($course->id);
1445
        $this->assertEquals('Dog', $data->myselect);
1446
    }
1447
 
1448
    /**
1449
     * Test upload processing of course custom field with an invalid select option
1450
     */
1451
    public function test_custom_fields_data_invalid_select_option() {
1452
        $this->resetAfterTest();
1453
        $this->setAdminUser();
1454
 
1455
        $course = $this->getDataGenerator()->create_course(['shortname' => 'C1']);
1456
 
1457
        // Create our custom field.
1458
        $category = $this->get_customfield_generator()->create_category();
1459
        $this->create_custom_field($category, 'select', 'myselect',
1460
            ['required' => true, 'options' => "Cat\nDog", 'defaultvalue' => 'Cat']);
1461
 
1462
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1463
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1464
        $dataupload = [
1465
            'shortname' => $course->shortname,
1466
            'customfield_myselect' => 'Fish', // No, invalid.
1467
        ];
1468
 
1469
        $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload);
1470
        $this->assertTrue($uploader->prepare());
1471
        $uploader->proceed();
1472
 
1473
        // Confirm presence of course custom fields.
1474
        $data = \core_course\customfield\course_handler::create()->export_instance_data_object($course->id);
1475
        $this->assertEquals('Cat', $data->myselect);
1476
    }
1477
 
1478
    /**
1479
     * Test upload processing of course custom field with an out of range date
1480
     */
1481
    public function test_custom_fields_data_invalid_date() {
1482
        $this->resetAfterTest();
1483
        $this->setAdminUser();
1484
 
1485
        $course = $this->getDataGenerator()->create_course(['shortname' => 'C1']);
1486
 
1487
        // Create our custom field.
1488
        $category = $this->get_customfield_generator()->create_category();
1489
        $this->create_custom_field($category, 'date', 'mydate',
1490
            ['mindate' => strtotime('2020-04-01'), 'maxdate' => '2020-04-30']);
1491
 
1492
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1493
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1494
        $dataupload = [
1495
            'shortname' => $course->shortname,
1496
            'customfield_mydate' => '2020-05-06', // Out of range.
1497
        ];
1498
 
1499
        $uploader = new tool_uploadcourse_course($mode, $updatemode, $dataupload);
1500
        $this->assertFalse($uploader->prepare());
1501
        $this->assertArrayHasKey('customfieldinvalid', $uploader->get_errors());
1502
    }
1503
 
1504
    public function test_idnumber_problems() {
1505
        $this->initialise_test();
1506
 
1507
        $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'sntaken', 'idnumber' => 'taken'));
1508
        $c2 = $this->getDataGenerator()->create_course();
1509
 
1510
        // Create with existing ID number.
1511
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1512
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1513
        $data = array('shortname' => 'c2', 'summary' => 'summary', 'fullname' => 'FN', 'category' => '1',
1514
            'idnumber' => $c1->idnumber);
1515
        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
1516
        $this->assertFalse($co->prepare());
1517
        $this->assertArrayHasKey('idnumberalreadyinuse', $co->get_errors());
1518
 
1519
        // Rename to existing ID number.
1520
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1521
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1522
        $data = array('shortname' => $c2->shortname, 'rename' => 'SN', 'idnumber' => $c1->idnumber);
1523
        $importoptions = array('canrename' => true);
1524
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1525
        $this->assertFalse($co->prepare());
1526
        $this->assertArrayHasKey('cannotrenameidnumberconflict', $co->get_errors());
1527
 
1528
        // Incrementing shortname increments idnumber.
1529
        $mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
1530
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
1531
        $data = array('shortname' => $c1->shortname, 'idnumber' => $c1->idnumber, 'summary' => 'S', 'fullname' => 'F',
1532
            'category' => 1);
1533
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array());
1534
        $this->assertTrue($co->prepare());
1535
        $this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses());
1536
        $this->assertArrayHasKey('courseidnumberincremented', $co->get_statuses());
1537
        $data = $co->get_data();
1538
        $this->assertEquals('sntaken_2', $data['shortname']);
1539
        $this->assertEquals('taken_2', $data['idnumber']);
1540
 
1541
        // Incrementing shortname increments idnumber unless available.
1542
        $mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
1543
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
1544
        $data = array('shortname' => $c1->shortname, 'idnumber' => 'nottaken', 'summary' => 'S', 'fullname' => 'F',
1545
            'category' => 1);
1546
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array());
1547
        $this->assertTrue($co->prepare());
1548
        $this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses());
1549
        $this->assertArrayNotHasKey('courseidnumberincremented', $co->get_statuses());
1550
        $data = $co->get_data();
1551
        $this->assertEquals('sntaken_2', $data['shortname']);
1552
        $this->assertEquals('nottaken', $data['idnumber']);
1553
    }
1554
 
1555
    public function test_generate_shortname() {
1556
        $this->initialise_test();
1557
 
1558
        $c1 = $this->getDataGenerator()->create_course(array('shortname' => 'taken'));
1559
 
1560
        // Generate a shortname.
1561
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1562
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
1563
        $data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1', 'idnumber' => 'IDN');
1564
        $importoptions = array('shortnametemplate' => '%i');
1565
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1566
        $this->assertTrue($co->prepare());
1567
        $this->assertArrayHasKey('courseshortnamegenerated', $co->get_statuses());
1568
 
1569
        // Generate a shortname without a template.
1570
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1571
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
1572
        $data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1');
1573
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array());
1574
        $this->assertFalse($co->prepare());
1575
        $this->assertArrayHasKey('missingshortnamenotemplate', $co->get_errors());
1576
 
1577
        // Generate a shortname in update mode.
1578
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1579
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1580
        $data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1');
1581
        $importoptions = array('shortnametemplate' => '%f');
1582
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1583
        $this->assertFalse($co->prepare());
1584
        // Commented because we never get here as the course without shortname does not exist.
1585
        // $this->assertArrayHasKey('cannotgenerateshortnameupdatemode', $co->get_errors());
1586
 
1587
        // Generate a shortname to a course that already exists.
1588
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1589
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
1590
        $data = array('summary' => 'summary', 'fullname' => 'taken', 'category' => '1');
1591
        $importoptions = array('shortnametemplate' => '%f');
1592
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1593
        $this->assertFalse($co->prepare());
1594
        $this->assertArrayHasKey('generatedshortnamealreadyinuse', $co->get_errors());
1595
 
1596
        // Generate a shortname to a course that already exists will be incremented.
1597
        $mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
1598
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
1599
        $data = array('summary' => 'summary', 'fullname' => 'taken', 'category' => '1');
1600
        $importoptions = array('shortnametemplate' => '%f');
1601
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1602
        $this->assertTrue($co->prepare());
1603
        $this->assertArrayHasKey('courseshortnamegenerated', $co->get_statuses());
1604
        $this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses());
1605
    }
1606
 
1607
    public function test_mess_with_frontpage() {
1608
        global $SITE;
1609
        $this->initialise_test();
1610
 
1611
        // Updating the front page.
1612
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1613
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1614
        $data = array('shortname' => $SITE->shortname, 'idnumber' => 'NewIDN');
1615
        $importoptions = array();
1616
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1617
        $this->assertFalse($co->prepare());
1618
        $this->assertArrayHasKey('cannotupdatefrontpage', $co->get_errors());
1619
 
1620
        // Updating the front page.
1621
        $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
1622
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1623
        $data = array('shortname' => $SITE->shortname, 'idnumber' => 'NewIDN');
1624
        $importoptions = array();
1625
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1626
        $this->assertFalse($co->prepare());
1627
        $this->assertArrayHasKey('cannotupdatefrontpage', $co->get_errors());
1628
 
1629
        // Generating a shortname should not be allowed in update mode, and so we cannot update the front page.
1630
        $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
1631
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1632
        $data = array('idnumber' => 'NewIDN', 'fullname' => 'FN', 'category' => 1);
1633
        $importoptions = array('shortnametemplate' => $SITE->shortname);
1634
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1635
        $this->assertFalse($co->prepare());
1636
        $this->assertArrayHasKey('cannotgenerateshortnameupdatemode', $co->get_errors());
1637
 
1638
        // Renaming to the front page should not be allowed.
1639
        $c1 = $this->getDataGenerator()->create_course();
1640
        $mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
1641
        $updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
1642
        $data = array('shortname' => $c1->shortname, 'fullname' => 'FN', 'idnumber' => 'NewIDN', 'rename' => $SITE->shortname);
1643
        $importoptions = array('canrename' => true);
1644
        $co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
1645
        $this->assertFalse($co->prepare());
1646
        $this->assertArrayHasKey('cannotrenameshortnamealreadyinuse', $co->get_errors());
1647
    }
1648
 
1649
    /**
1650
     * Test when role doesn't exist.
1651
     *
1652
     * @covers \tool_uploadcourse_course::prepare
1653
     */
1654
    public function test_role_not_exist() {
1655
        $this->resetAfterTest();
1656
        $this->setAdminUser();
1657
 
1658
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1659
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
1660
 
1661
        $upload = new tool_uploadcourse_course($mode, $updatemode, [
1662
            'category' => 1,
1663
            'fullname' => 'Testing',
1664
            'shortname' => 'T101',
1665
            'enrolment_1' => 'manual',
1666
            'enrolment_1_role' => 'notexist'
1667
        ]);
1668
 
1669
        $this->assertFalse($upload->prepare());
1670
        $this->assertArrayHasKey('invalidroles', $upload->get_errors());
1671
    }
1672
 
1673
    /**
1674
     * Test when role not allowed in course context.
1675
     *
1676
     * @covers \tool_uploadcourse_course::proceed
1677
     */
1678
    public function test_role_not_allowed() {
1679
        $this->resetAfterTest();
1680
        $this->setAdminUser();
1681
 
1682
        $roleid = create_role('New student role', 'student2', 'New student description', 'student');
1683
        set_role_contextlevels($roleid, [CONTEXT_BLOCK]);
1684
 
1685
        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
1686
        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
1687
 
1688
        $upload = new tool_uploadcourse_course($mode, $updatemode, [
1689
            'category' => 1,
1690
            'fullname' => 'Testing',
1691
            'shortname' => 'T101',
1692
            'enrolment_1' => 'manual',
1693
            'enrolment_1_role' => 'student2'
1694
        ]);
1695
 
1696
        $this->assertFalse($upload->prepare());
1697
        $this->assertArrayHasKey('contextrolenotallowed', $upload->get_errors());
1698
    }
1699
 
1700
    /**
1701
     * Test when role is allowed.
1702
     *
1703
     * @covers \tool_uploadcourse_course::proceed
1704
     */
1705
    public function test_role_allowed() {
1706
        global $DB;
1707
 
1708
        $this->resetAfterTest();
1709
        $this->setAdminUser();
1710
 
1711
        $mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
1712
        $updatemode = tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS;
1713
 
1714
        $course = $this->getDataGenerator()->create_course([
1715
            'shortname' => 'c1',
1716
        ]);
1717
 
1718
        $instances = enrol_get_instances($course->id, true);
1719
        $studentrole = $DB->get_record('role', ['shortname' => 'student']);
1720
        $teacherrole = $DB->get_record('role', ['shortname' => 'teacher']);
1721
        $instance = reset($instances);
1722
        $this->assertEquals($studentrole->id, $instance->roleid);
1723
 
1724
        $upload = new tool_uploadcourse_course($mode, $updatemode, [
1725
            'shortname' => 'c1',
1726
            'enrolment_1' => 'manual',
1727
            'enrolment_1_role' => 'teacher'
1728
        ]);
1729
 
1730
        $this->assertTrue($upload->prepare());
1731
        $upload->proceed();
1732
        $instances = enrol_get_instances($course->id, true);
1733
        $instance = reset($instances);
1734
        $this->assertEquals($teacherrole->id, $instance->roleid);
1735
    }
1736
 
1737
    /**
1738
     * Get custom field plugin generator
1739
     *
1740
     * @return core_customfield_generator
1741
     */
1742
    protected function get_customfield_generator(): \core_customfield_generator {
1743
        return $this->getDataGenerator()->get_plugin_generator('core_customfield');
1744
    }
1745
 
1746
    /**
1747
     * Helper method to create custom course field
1748
     *
1749
     * @param \core_customfield\category_controller $category
1750
     * @param string $type
1751
     * @param string $shortname
1752
     * @param array $configdata
1753
     * @return \core_customfield\field_controller
1754
     */
1755
    protected function create_custom_field(\core_customfield\category_controller $category, string $type, string $shortname,
1756
            array $configdata = []): \core_customfield\field_controller {
1757
 
1758
        return $this->get_customfield_generator()->create_field([
1759
            'categoryid' => $category->get('id'),
1760
            'type' => $type,
1761
            'shortname' => $shortname,
1762
            'configdata' => $configdata,
1763
        ]);
1764
    }
1765
}