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
namespace core_course\backup;
18
 
19
use backup;
20
use backup_controller;
21
use restore_controller;
22
use restore_dbops;
23
 
24
defined('MOODLE_INTERNAL') || die();
25
global $CFG;
26
 
27
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
28
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
29
require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest.php');
30
 
31
/**
32
 * Course restore testcase.
33
 *
34
 * @package    core_course
35
 * @copyright  2016 Frédéric Massart - FMCorz.net
36
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37
 */
1441 ariadna 38
final class restore_test extends \advanced_testcase {
1 efrain 39
 
40
    /**
41
     * Backup a course and return its backup ID.
42
     *
43
     * @param int $courseid The course ID.
44
     * @param int $userid The user doing the backup.
45
     * @return string
46
     */
47
    protected function backup_course($courseid, $userid = 2) {
48
        $backuptempdir = make_backup_temp_directory('');
49
        $packer = get_file_packer('application/vnd.moodle.backup');
50
 
51
        $bc = new backup_controller(backup::TYPE_1COURSE, $courseid, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO,
52
            backup::MODE_GENERAL, $userid);
53
        $bc->execute_plan();
54
 
55
        $results = $bc->get_results();
56
        $results['backup_destination']->extract_to_pathname($packer, "$backuptempdir/core_course_testcase");
57
 
58
        $bc->destroy();
59
        unset($bc);
60
        return 'core_course_testcase';
61
    }
62
 
63
    /**
64
     * Create a role with capabilities and permissions.
65
     *
66
     * @param string|array $caps Capability names.
67
     * @param int $perm Constant CAP_* to apply to the capabilities.
68
     * @return int The new role ID.
69
     */
70
    protected function create_role_with_caps($caps, $perm) {
71
        $caps = (array) $caps;
72
        $dg = $this->getDataGenerator();
73
        $roleid = $dg->create_role();
74
        foreach ($caps as $cap) {
75
            assign_capability($cap, $perm, $roleid, \context_system::instance()->id, true);
76
        }
77
        accesslib_clear_all_caches_for_unit_testing();
78
        return $roleid;
79
    }
80
 
81
    /**
82
     * Restore a course.
83
     *
84
     * @param int $backupid The backup ID.
85
     * @param int $courseid The course ID to restore in, or 0.
86
     * @param int $userid The ID of the user performing the restore.
87
     * @return stdClass The updated course object.
88
     */
89
    protected function restore_course($backupid, $courseid, $userid) {
90
        global $DB;
91
 
92
        $target = backup::TARGET_CURRENT_ADDING;
93
        if (!$courseid) {
94
            $target = backup::TARGET_NEW_COURSE;
95
            $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
96
            $courseid = restore_dbops::create_new_course('Tmp', 'tmp', $categoryid);
97
        }
98
 
99
        $rc = new restore_controller($backupid, $courseid, backup::INTERACTIVE_NO, backup::MODE_GENERAL, $userid, $target);
100
        $target == backup::TARGET_NEW_COURSE ?: $rc->get_plan()->get_setting('overwrite_conf')->set_value(true);
101
        $this->assertTrue($rc->execute_precheck());
102
        $rc->execute_plan();
103
 
104
        $course = $DB->get_record('course', array('id' => $rc->get_courseid()));
105
 
106
        $rc->destroy();
107
        unset($rc);
108
        return $course;
109
    }
110
 
111
    /**
112
     * Restore a course to an existing course.
113
     *
114
     * @param int $backupid The backup ID.
115
     * @param int $courseid The course ID to restore in.
116
     * @param int $userid The ID of the user performing the restore.
117
     * @return stdClass The updated course object.
118
     */
119
    protected function restore_to_existing_course($backupid, $courseid, $userid = 2) {
120
        return $this->restore_course($backupid, $courseid, $userid);
121
    }
122
 
123
    /**
124
     * Restore a course to a new course.
125
     *
126
     * @param int $backupid The backup ID.
127
     * @param int $userid The ID of the user performing the restore.
128
     * @return stdClass The new course object.
129
     */
130
    protected function restore_to_new_course($backupid, $userid = 2) {
131
        return $this->restore_course($backupid, 0, $userid);
132
    }
133
 
134
    /**
135
     * Restore a course.
136
     *
137
     * @param int $backupid The backup ID.
138
     * @param int $courseid The course ID to restore in, or 0.
139
     * @param int $userid The ID of the user performing the restore.
140
     * @param int $target THe target of the restore.
141
     *
142
     * @return stdClass The updated course object.
143
     */
144
    protected function async_restore_course($backupid, $courseid, $userid, $target) {
145
        global $DB;
146
 
147
        if (!$courseid) {
148
            $target = backup::TARGET_NEW_COURSE;
149
            $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
150
            $courseid = restore_dbops::create_new_course('Tmp', 'tmp', $categoryid);
151
        }
152
 
153
        $rc = new restore_controller($backupid, $courseid, backup::INTERACTIVE_NO, backup::MODE_ASYNC, $userid, $target);
154
        $target == backup::TARGET_NEW_COURSE ?: $rc->get_plan()->get_setting('overwrite_conf')->set_value(true);
155
        $this->assertTrue($rc->execute_precheck());
156
 
157
        $restoreid = $rc->get_restoreid();
158
        $rc->destroy();
159
 
160
        // Create the adhoc task.
161
        $asynctask = new \core\task\asynchronous_restore_task();
162
        $asynctask->set_custom_data(array('backupid' => $restoreid));
163
        \core\task\manager::queue_adhoc_task($asynctask);
164
 
165
        // We are expecting trace output during this test.
166
        $this->expectOutputRegex("/$restoreid/");
167
 
168
        // Execute adhoc task.
169
        $now = time();
170
        $task = \core\task\manager::get_next_adhoc_task($now);
171
        $this->assertInstanceOf('\\core\\task\\asynchronous_restore_task', $task);
172
        $task->execute();
173
        \core\task\manager::adhoc_task_complete($task);
174
 
175
        $course = $DB->get_record('course', array('id' => $rc->get_courseid()));
176
 
177
        return $course;
178
    }
179
 
180
    /**
181
     * Restore a course to an existing course.
182
     *
183
     * @param int $backupid The backup ID.
184
     * @param int $courseid The course ID to restore in.
185
     * @param int $userid The ID of the user performing the restore.
186
     * @param int $target The type of restore we are performing.
187
     * @return stdClass The updated course object.
188
     */
189
    protected function async_restore_to_existing_course($backupid, $courseid,
190
        $userid = 2, $target = backup::TARGET_CURRENT_ADDING) {
191
        return $this->async_restore_course($backupid, $courseid, $userid, $target);
192
    }
193
 
194
    /**
195
     * Restore a course to a new course.
196
     *
197
     * @param int $backupid The backup ID.
198
     * @param int $userid The ID of the user performing the restore.
199
     * @return stdClass The new course object.
200
     */
201
    protected function async_restore_to_new_course($backupid, $userid = 2) {
202
        return $this->async_restore_course($backupid, 0, $userid, 0);
203
    }
204
 
11 efrain 205
    public function test_async_restore_existing_idnumber_in_new_course(): void {
1 efrain 206
        $this->resetAfterTest();
207
 
208
        $dg = $this->getDataGenerator();
209
        $c1 = $dg->create_course(['idnumber' => 'ABC']);
210
        $backupid = $this->backup_course($c1->id);
211
        $c2 = $this->async_restore_to_new_course($backupid);
212
 
213
        // The ID number is set empty.
214
        $this->assertEquals('', $c2->idnumber);
215
    }
216
 
11 efrain 217
    public function test_async_restore_course_info_in_existing_course(): void {
1 efrain 218
        global $DB;
219
        $this->resetAfterTest();
220
        $dg = $this->getDataGenerator();
221
 
222
        $this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
223
        $this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
224
        $this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
225
 
226
        $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
227
 
1441 ariadna 228
        // Create two courses with different start dates, in each course create an assignment
229
        // that is due 1 week after the course start date.
1 efrain 230
        $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
231
            'startdate' => $startdate]);
1441 ariadna 232
        $assign1 = $dg->create_module('assign',
233
            ['name' => 'First', 'course' => $c1->id, 'duedate' => $c1->startdate + 1 * WEEKSECS]
234
        );
1 efrain 235
        $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
236
            'startdate' => $startdate + 2 * WEEKSECS]);
1441 ariadna 237
        $assign2 = $dg->create_module('assign',
238
            ['name' => 'Second', 'course' => $c2->id, 'duedate' => $c2->startdate + 1 * WEEKSECS]
239
        );
1 efrain 240
        $backupid = $this->backup_course($c1->id);
241
 
242
        // The information is restored but adapted because names are already taken.
243
        $c2 = $this->async_restore_to_existing_course($backupid, $c2->id);
244
        $this->assertEquals('SN_1', $c2->shortname);
245
        $this->assertEquals('FN copy 1', $c2->fullname);
246
        $this->assertEquals('DESC', $c2->summary);
247
        $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
248
        $this->assertEquals($startdate, $c2->startdate);
249
 
1441 ariadna 250
        // Now course c2 has two assignments - one ('Second') was already there and one ('First') was restored from the backup.
1 efrain 251
        // Their dates are exactly the same as they were in the original modules.
1441 ariadna 252
        $restoredassign1 = $DB->get_record('assign', ['name' => 'First', 'course' => $c2->id]);
253
        $restoredassign2 = $DB->get_record('assign', ['name' => 'Second', 'course' => $c2->id]);
254
        $this->assertEquals($assign1->duedate, $restoredassign1->duedate);
255
        $this->assertEquals($assign2->duedate, $restoredassign2->duedate);
1 efrain 256
    }
257
 
11 efrain 258
    public function test_async_restore_course_info_in_existing_course_delete_first(): void {
1 efrain 259
        global $DB;
260
        $this->resetAfterTest();
261
        $dg = $this->getDataGenerator();
262
 
263
        $this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
264
        $this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
265
        $this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
266
 
267
        $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
268
 
1441 ariadna 269
        // Create two courses with different start dates, in each course create an assignment
270
        // that is due 1 week after the course start date.
1 efrain 271
        $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
272
            'startdate' => $startdate]);
1441 ariadna 273
        $assign1 = $dg->create_module('assign',
274
            ['name' => 'First', 'course' => $c1->id, 'duedate' => $c1->startdate + 1 * WEEKSECS]
275
        );
1 efrain 276
        $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
277
            'startdate' => $startdate + 2 * WEEKSECS]);
1441 ariadna 278
        $assign2 = $dg->create_module('assign',
279
            ['name' => 'Second', 'course' => $c2->id, 'duedate' => $c2->startdate + 1 * WEEKSECS]
280
        );
1 efrain 281
        $backupid = $this->backup_course($c1->id);
282
 
283
        // The information is restored and the existing course settings is modified.
284
        $c2 = $this->async_restore_to_existing_course($backupid, $c2->id, 2, backup::TARGET_CURRENT_DELETING);
285
        $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
286
 
1441 ariadna 287
        // Now course2 should have a new assignment with the original assignment deleted.
288
        $restoredassign1 = $DB->get_record('assign', ['name' => 'First', 'course' => $c2->id]);
289
        $restoredassign2 = $DB->get_record('assign', ['name' => 'Second', 'course' => $c2->id]);
290
        $this->assertEquals($assign1->duedate, $restoredassign1->duedate);
291
        $this->assertEmpty($restoredassign2);
1 efrain 292
    }
293
 
11 efrain 294
    public function test_restore_existing_idnumber_in_new_course(): void {
1 efrain 295
        $this->resetAfterTest();
296
 
297
        $dg = $this->getDataGenerator();
298
        $c1 = $dg->create_course(['idnumber' => 'ABC']);
299
        $backupid = $this->backup_course($c1->id);
300
        $c2 = $this->restore_to_new_course($backupid);
301
 
302
        // The ID number is set empty.
303
        $this->assertEquals('', $c2->idnumber);
304
    }
305
 
11 efrain 306
    public function test_restore_non_existing_idnumber_in_new_course(): void {
1 efrain 307
        global $DB;
308
        $this->resetAfterTest();
309
 
310
        $dg = $this->getDataGenerator();
311
        $c1 = $dg->create_course(['idnumber' => 'ABC']);
312
        $backupid = $this->backup_course($c1->id);
313
 
314
        $c1->idnumber = 'BCD';
315
        $DB->update_record('course', $c1);
316
 
317
        // The ID number changed.
318
        $c2 = $this->restore_to_new_course($backupid);
319
        $this->assertEquals('ABC', $c2->idnumber);
320
    }
321
 
11 efrain 322
    public function test_restore_existing_idnumber_in_existing_course(): void {
1 efrain 323
        global $DB;
324
        $this->resetAfterTest();
325
 
326
        $dg = $this->getDataGenerator();
327
        $c1 = $dg->create_course(['idnumber' => 'ABC']);
328
        $c2 = $dg->create_course(['idnumber' => 'DEF']);
329
        $backupid = $this->backup_course($c1->id);
330
 
331
        // The ID number does not change.
332
        $c2 = $this->restore_to_existing_course($backupid, $c2->id);
333
        $this->assertEquals('DEF', $c2->idnumber);
334
 
335
        $c1 = $DB->get_record('course', array('id' => $c1->id));
336
        $this->assertEquals('ABC', $c1->idnumber);
337
    }
338
 
11 efrain 339
    public function test_restore_non_existing_idnumber_in_existing_course(): void {
1 efrain 340
        global $DB;
341
        $this->resetAfterTest();
342
 
343
        $dg = $this->getDataGenerator();
344
        $c1 = $dg->create_course(['idnumber' => 'ABC']);
345
        $c2 = $dg->create_course(['idnumber' => 'DEF']);
346
        $backupid = $this->backup_course($c1->id);
347
 
348
        $c1->idnumber = 'XXX';
349
        $DB->update_record('course', $c1);
350
 
351
        // The ID number has changed.
352
        $c2 = $this->restore_to_existing_course($backupid, $c2->id);
353
        $this->assertEquals('ABC', $c2->idnumber);
354
    }
355
 
11 efrain 356
    public function test_restore_idnumber_in_existing_course_without_permissions(): void {
1 efrain 357
        global $DB;
358
        $this->resetAfterTest();
359
        $dg = $this->getDataGenerator();
360
        $u1 = $dg->create_user();
361
 
362
        $managers = get_archetype_roles('manager');
363
        $manager = array_shift($managers);
364
        $roleid = $this->create_role_with_caps('moodle/course:changeidnumber', CAP_PROHIBIT);
365
        $dg->role_assign($manager->id, $u1->id);
366
        $dg->role_assign($roleid, $u1->id);
367
 
368
        $c1 = $dg->create_course(['idnumber' => 'ABC']);
369
        $c2 = $dg->create_course(['idnumber' => 'DEF']);
370
        $backupid = $this->backup_course($c1->id);
371
 
372
        $c1->idnumber = 'XXX';
373
        $DB->update_record('course', $c1);
374
 
375
        // The ID number does not change.
376
        $c2 = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
377
        $this->assertEquals('DEF', $c2->idnumber);
378
    }
379
 
11 efrain 380
    public function test_restore_course_info_in_new_course(): void {
1 efrain 381
        global $DB;
382
        $this->resetAfterTest();
383
        $dg = $this->getDataGenerator();
384
 
385
        $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
386
 
387
        $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'startdate' => $startdate,
388
            'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
389
        $backupid = $this->backup_course($c1->id);
390
 
391
        // The information is restored but adapted because names are already taken.
392
        $c2 = $this->restore_to_new_course($backupid);
393
        $this->assertEquals('SN_1', $c2->shortname);
394
        $this->assertEquals('FN copy 1', $c2->fullname);
395
        $this->assertEquals('DESC', $c2->summary);
396
        $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
397
        $this->assertEquals($startdate, $c2->startdate);
398
    }
399
 
11 efrain 400
    public function test_restore_course_with_users(): void {
1 efrain 401
        global $DB;
402
        $this->resetAfterTest();
403
        $this->setAdminUser();
404
        $dg = $this->getDataGenerator();
405
 
406
        // Create a user and a course, enrol user in the course. Backup this course.
407
        $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
408
        $u1 = $dg->create_user(['firstname' => 'Olivia']);
409
        $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'startdate' => $startdate,
410
            'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
411
        $dg->enrol_user($u1->id, $c1->id, 'student');
412
        $backupid = $this->backup_course($c1->id);
413
 
414
        // Delete the course and the user completely.
415
        delete_course($c1, false);
416
        delete_user($u1);
417
        $DB->delete_records('user', ['id' => $u1->id]);
418
 
419
        // Now restore this course, the user will be created and event user_created event will be triggered.
420
        $sink = $this->redirectEvents();
421
        $c2 = $this->restore_to_new_course($backupid);
422
        $events = $sink->get_events();
423
        $sink->close();
424
 
425
        $user = $DB->get_record('user', ['firstname' => 'Olivia'], '*', MUST_EXIST);
426
        $events = array_values(array_filter($events, function(\core\event\base $event) {
427
            return is_a($event, \core\event\user_created::class);
428
        }));
429
        $this->assertEquals(1, count($events));
430
        $this->assertEquals($user->id, $events[0]->relateduserid);
431
        $this->assertEquals($c2->id, $events[0]->other['courseid']);
432
        $this->assertStringContainsString("during restore of the course with id '{$c2->id}'",
433
            $events[0]->get_description());
434
    }
435
 
11 efrain 436
    public function test_restore_course_info_in_existing_course(): void {
1 efrain 437
        global $DB;
438
        $this->resetAfterTest();
439
        $dg = $this->getDataGenerator();
440
 
441
        $this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
442
        $this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
443
        $this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
444
 
445
        $startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
446
 
1441 ariadna 447
        // Create two courses with different start dates,in each course create an assignment
448
        // that opens 1 week after the course start date.
1 efrain 449
        $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
450
            'startdate' => $startdate]);
1441 ariadna 451
        $assign1 = $dg->create_module('assign',
452
            ['name' => 'First', 'course' => $c1->id, 'duedate' => $c1->startdate + 1 * WEEKSECS]
453
        );
1 efrain 454
        $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
455
            'startdate' => $startdate + 2 * WEEKSECS]);
1441 ariadna 456
        $assign2 = $dg->create_module('assign',
457
            ['name' => 'Second', 'course' => $c2->id, 'duedate' => $c2->startdate + 1 * WEEKSECS]
458
        );
1 efrain 459
        $backupid = $this->backup_course($c1->id);
460
 
461
        // The information is restored but adapted because names are already taken.
462
        $c2 = $this->restore_to_existing_course($backupid, $c2->id);
463
        $this->assertEquals('SN_1', $c2->shortname);
464
        $this->assertEquals('FN copy 1', $c2->fullname);
465
        $this->assertEquals('DESC', $c2->summary);
466
        $this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
467
        $this->assertEquals($startdate, $c2->startdate);
468
 
469
        // Now course c2 has two chats - one ('Second') was already there and one ('First') was restored from the backup.
470
        // Their dates are exactly the same as they were in the original modules.
1441 ariadna 471
        $restoredassign1 = $DB->get_record('assign', ['name' => 'First', 'course' => $c2->id]);
472
        $restoredassign2 = $DB->get_record('assign', ['name' => 'Second', 'course' => $c2->id]);
473
        $this->assertEquals($assign1->duedate, $restoredassign1->duedate);
474
        $this->assertEquals($assign2->duedate, $restoredassign2->duedate);
1 efrain 475
    }
476
 
11 efrain 477
    public function test_restore_course_shortname_in_existing_course_without_permissions(): void {
1 efrain 478
        global $DB;
479
        $this->resetAfterTest();
480
        $dg = $this->getDataGenerator();
481
        $u1 = $dg->create_user();
482
 
483
        $managers = get_archetype_roles('manager');
484
        $manager = array_shift($managers);
485
        $roleid = $this->create_role_with_caps('moodle/course:changeshortname', CAP_PROHIBIT);
486
        $dg->role_assign($manager->id, $u1->id);
487
        $dg->role_assign($roleid, $u1->id);
488
 
489
        $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
490
        $c2 = $dg->create_course(['shortname' => 'A1', 'fullname' => 'B1', 'summary' => 'C1', 'summaryformat' => FORMAT_PLAIN]);
491
 
492
        // The shortname does not change.
493
        $backupid = $this->backup_course($c1->id);
494
        $restored = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
495
        $this->assertEquals($c2->shortname, $restored->shortname);
496
        $this->assertEquals('FN copy 1', $restored->fullname);
497
        $this->assertEquals('DESC', $restored->summary);
498
        $this->assertEquals(FORMAT_MOODLE, $restored->summaryformat);
499
    }
500
 
11 efrain 501
    public function test_restore_course_fullname_in_existing_course_without_permissions(): void {
1 efrain 502
        global $DB;
503
        $this->resetAfterTest();
504
        $dg = $this->getDataGenerator();
505
        $u1 = $dg->create_user();
506
 
507
        $managers = get_archetype_roles('manager');
508
        $manager = array_shift($managers);
509
        $roleid = $this->create_role_with_caps('moodle/course:changefullname', CAP_PROHIBIT);
510
        $dg->role_assign($manager->id, $u1->id);
511
        $dg->role_assign($roleid, $u1->id);
512
 
513
        $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
514
        $c2 = $dg->create_course(['shortname' => 'A1', 'fullname' => 'B1', 'summary' => 'C1', 'summaryformat' => FORMAT_PLAIN]);
515
 
516
        // The fullname does not change.
517
        $backupid = $this->backup_course($c1->id);
518
        $restored = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
519
        $this->assertEquals('SN_1', $restored->shortname);
520
        $this->assertEquals($c2->fullname, $restored->fullname);
521
        $this->assertEquals('DESC', $restored->summary);
522
        $this->assertEquals(FORMAT_MOODLE, $restored->summaryformat);
523
    }
524
 
11 efrain 525
    public function test_restore_course_summary_in_existing_course_without_permissions(): void {
1 efrain 526
        global $DB;
527
        $this->resetAfterTest();
528
        $dg = $this->getDataGenerator();
529
        $u1 = $dg->create_user();
530
 
531
        $managers = get_archetype_roles('manager');
532
        $manager = array_shift($managers);
533
        $roleid = $this->create_role_with_caps('moodle/course:changesummary', CAP_PROHIBIT);
534
        $dg->role_assign($manager->id, $u1->id);
535
        $dg->role_assign($roleid, $u1->id);
536
 
537
        $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE]);
538
        $c2 = $dg->create_course(['shortname' => 'A1', 'fullname' => 'B1', 'summary' => 'C1', 'summaryformat' => FORMAT_PLAIN]);
539
 
540
        // The summary and format do not change.
541
        $backupid = $this->backup_course($c1->id);
542
        $restored = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
543
        $this->assertEquals('SN_1', $restored->shortname);
544
        $this->assertEquals('FN copy 1', $restored->fullname);
545
        $this->assertEquals($c2->summary, $restored->summary);
546
        $this->assertEquals($c2->summaryformat, $restored->summaryformat);
547
    }
548
 
11 efrain 549
    public function test_restore_course_startdate_in_existing_course_without_permissions(): void {
1 efrain 550
        global $DB;
551
        $this->resetAfterTest();
552
        $dg = $this->getDataGenerator();
553
 
554
        $u1 = $dg->create_user();
555
        $managers = get_archetype_roles('manager');
556
        $manager = array_shift($managers);
557
        $roleid = $this->create_role_with_caps('moodle/restore:rolldates', CAP_PROHIBIT);
558
        $dg->role_assign($manager->id, $u1->id);
559
        $dg->role_assign($roleid, $u1->id);
560
 
1441 ariadna 561
        // Create two courses with different start dates, in each course create an assignment that
562
        // is due 1 week after the course start date.
1 efrain 563
        $startdate1 = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
564
        $startdate2 = mktime(12, 0, 0, 1, 13, 2000); // 13-Jan-2000.
565
        $c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
566
            'startdate' => $startdate1]);
1441 ariadna 567
        $assign1 = $dg->create_module('assign',
568
            ['name' => 'First', 'course' => $c1->id, 'duedate' => $c1->startdate + 1 * WEEKSECS]
569
        );
1 efrain 570
        $c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
571
            'startdate' => $startdate2]);
1441 ariadna 572
        $assign2 = $dg->create_module('assign',
573
            ['name' => 'Second', 'course' => $c2->id, 'duedate' => $c2->startdate + 1 * WEEKSECS]
574
        );
1 efrain 575
 
576
        // The startdate does not change.
577
        $backupid = $this->backup_course($c1->id);
578
        $restored = $this->restore_to_existing_course($backupid, $c2->id, $u1->id);
579
        $this->assertEquals('SN_1', $restored->shortname);
580
        $this->assertEquals('FN copy 1', $restored->fullname);
581
        $this->assertEquals('DESC', $restored->summary);
582
        $this->assertEquals(FORMAT_MOODLE, $restored->summaryformat);
583
        $this->assertEquals($startdate2, $restored->startdate);
584
 
1441 ariadna 585
        // Now course c2 has two assignments - one ('Second') was already there and one ('First') was restored from the backup.
586
        // Start date of the restored assignment ('First') was changed to be 1 week after the c2 start date.
587
        $restoredassign1 = $DB->get_record('assign', ['name' => 'First', 'course' => $c2->id]);
588
        $restoredassign2 = $DB->get_record('assign', ['name' => 'Second', 'course' => $c2->id]);
589
        $this->assertNotEquals($assign1->duedate, $restoredassign1->duedate);
590
        $this->assertEquals($assign2->duedate, $restoredassign2->duedate);
591
        $this->assertEquals($c2->startdate + 1 * WEEKSECS, $restoredassign2->duedate);
1 efrain 592
    }
593
 
594
    /**
595
     * Tests course restore with editor in course format.
596
     *
597
     * @author Matthew Hilton
1441 ariadna 598
     * @covers \core_courseformat\base
599
     * @covers \backup_course_structure_step
600
     * @covers \restore_course_structure_step
1 efrain 601
     */
11 efrain 602
    public function test_restore_editor_courseformat(): void {
1 efrain 603
        $this->resetAfterTest();
604
 
605
        // Setup user with restore permissions.
606
        $dg = $this->getDataGenerator();
607
        $u1 = $dg->create_user();
608
 
609
        $managers = get_archetype_roles('manager');
610
        $manager = array_shift($managers);
611
        $dg->role_assign($manager->id, $u1->id);
612
 
613
        // Create a course with an editor item in the course format.
614
        $courseformatoptiondata = (object) [
615
            "hideoddsections" => 1,
616
            'summary_editor' => [
617
                'text' => '<p>Somewhere over the rainbow</p><p>The <b>quick</b> brown fox jumpos over the lazy dog.</p>',
618
                'format' => 1
619
            ]
620
        ];
621
        $course1 = $dg->create_course(['format' => 'theunittest']);
622
        $course2 = $dg->create_course(['format' => 'theunittest']);
623
        $this->assertEquals('theunittest', $course1->format);
624
        course_create_sections_if_missing($course1, array(0, 1));
625
 
626
        // Set the course format.
627
        $courseformat = course_get_format($course1);
628
        $courseformat->update_course_format_options($courseformatoptiondata);
629
 
630
        // Backup and restore the course.
631
        $backupid = $this->backup_course($course1->id);
632
        $this->restore_to_existing_course($backupid, $course2->id, $u1->id);
633
 
634
        // Get the restored course format.
635
        $restoredformat = course_get_format($course2);
636
        $restoredformatoptions = $restoredformat->get_format_options();
637
 
638
        $this->assertEqualsCanonicalizing($courseformatoptiondata, (object) $restoredformatoptions);
639
    }
640
}