Skip to content

Commit 8b44b91

Browse files
committed
Merge branch 'MDL-66021-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE
2 parents bfdc024 + 62566af commit 8b44b91

File tree

3 files changed

+175
-6
lines changed

3 files changed

+175
-6
lines changed

backup/controller/restore_controller.class.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,21 @@ public function get_executiontime() {
332332
public function get_plan() {
333333
return $this->plan;
334334
}
335+
/**
336+
* Gets the value for the requested setting
337+
*
338+
* @param string $name
339+
* @param bool $default
340+
* @return mixed
341+
*/
342+
public function get_setting_value($name, $default = false) {
343+
try {
344+
return $this->get_plan()->get_setting($name)->get_value();
345+
} catch (Exception $e) {
346+
debugging('Failed to find the setting: '.$name, DEBUG_DEVELOPER);
347+
return $default;
348+
}
349+
}
335350

336351
public function get_info() {
337352
return $this->info;
@@ -341,6 +356,14 @@ public function execute_plan() {
341356
// Basic/initial prevention against time/memory limits
342357
core_php_time_limit::raise(1 * 60 * 60); // 1 hour for 1 course initially granted
343358
raise_memory_limit(MEMORY_EXTRA);
359+
360+
// Do course cleanup precheck, if required. This was originally in restore_ui. Moved to handle async backup/restore.
361+
if ($this->get_target() == backup::TARGET_CURRENT_DELETING || $this->get_target() == backup::TARGET_EXISTING_DELETING) {
362+
$options = array();
363+
$options['keep_roles_and_enrolments'] = $this->get_setting_value('keep_roles_and_enrolments');
364+
$options['keep_groups_and_groupings'] = $this->get_setting_value('keep_groups_and_groupings');
365+
restore_dbops::delete_course_content($this->get_courseid(), $options);
366+
}
344367
// If this is not a course restore or single activity restore (e.g. duplicate), inform the plan we are not
345368
// including all the activities for sure. This will affect any
346369
// task/step executed conditionally to stop processing information

backup/util/ui/restore_ui.class.php

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,7 @@ public function execute() {
215215
if ($this->stage->get_stage() < self::STAGE_PROCESS) {
216216
throw new restore_ui_exception('restoreuifinalisedbeforeexecute');
217217
}
218-
if ($this->controller->get_target() == backup::TARGET_CURRENT_DELETING || $this->controller->get_target() == backup::TARGET_EXISTING_DELETING) {
219-
$options = array();
220-
$options['keep_roles_and_enrolments'] = $this->get_setting_value('keep_roles_and_enrolments');
221-
$options['keep_groups_and_groupings'] = $this->get_setting_value('keep_groups_and_groupings');
222-
restore_dbops::delete_course_content($this->controller->get_courseid(), $options);
223-
}
218+
224219
$this->controller->execute_plan();
225220
$this->progress = self::PROGRESS_EXECUTED;
226221
$this->stage = new restore_ui_stage_complete($this, $this->stage->get_params(), $this->controller->get_results());

course/tests/restore_test.php

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,157 @@ protected function restore_to_new_course($backupid, $userid = 2) {
131131
return $this->restore_course($backupid, 0, $userid);
132132
}
133133

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_blocking(false);
163+
$asynctask->set_custom_data(array('backupid' => $restoreid));
164+
\core\task\manager::queue_adhoc_task($asynctask);
165+
166+
// We are expecting trace output during this test.
167+
$this->expectOutputRegex("/$restoreid/");
168+
169+
// Execute adhoc task.
170+
$now = time();
171+
$task = \core\task\manager::get_next_adhoc_task($now);
172+
$this->assertInstanceOf('\\core\\task\\asynchronous_restore_task', $task);
173+
$task->execute();
174+
\core\task\manager::adhoc_task_complete($task);
175+
176+
$course = $DB->get_record('course', array('id' => $rc->get_courseid()));
177+
178+
return $course;
179+
}
180+
181+
/**
182+
* Restore a course to an existing course.
183+
*
184+
* @param int $backupid The backup ID.
185+
* @param int $courseid The course ID to restore in.
186+
* @param int $userid The ID of the user performing the restore.
187+
* @param int $target The type of restore we are performing.
188+
* @return stdClass The updated course object.
189+
*/
190+
protected function async_restore_to_existing_course($backupid, $courseid,
191+
$userid = 2, $target = backup::TARGET_CURRENT_ADDING) {
192+
return $this->async_restore_course($backupid, $courseid, $userid, $target);
193+
}
194+
195+
/**
196+
* Restore a course to a new course.
197+
*
198+
* @param int $backupid The backup ID.
199+
* @param int $userid The ID of the user performing the restore.
200+
* @return stdClass The new course object.
201+
*/
202+
protected function async_restore_to_new_course($backupid, $userid = 2) {
203+
return $this->async_restore_course($backupid, 0, $userid, 0);
204+
}
205+
206+
public function test_async_restore_existing_idnumber_in_new_course() {
207+
$this->resetAfterTest();
208+
209+
$dg = $this->getDataGenerator();
210+
$c1 = $dg->create_course(['idnumber' => 'ABC']);
211+
$backupid = $this->backup_course($c1->id);
212+
$c2 = $this->async_restore_to_new_course($backupid);
213+
214+
// The ID number is set empty.
215+
$this->assertEquals('', $c2->idnumber);
216+
}
217+
218+
public function test_async_restore_course_info_in_existing_course() {
219+
global $DB;
220+
$this->resetAfterTest();
221+
$dg = $this->getDataGenerator();
222+
223+
$this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
224+
$this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
225+
$this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
226+
227+
$startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
228+
229+
// Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
230+
$c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
231+
'startdate' => $startdate]);
232+
$chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
233+
$c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
234+
'startdate' => $startdate + 2 * WEEKSECS]);
235+
$chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
236+
$backupid = $this->backup_course($c1->id);
237+
238+
// The information is restored but adapted because names are already taken.
239+
$c2 = $this->async_restore_to_existing_course($backupid, $c2->id);
240+
$this->assertEquals('SN_1', $c2->shortname);
241+
$this->assertEquals('FN copy 1', $c2->fullname);
242+
$this->assertEquals('DESC', $c2->summary);
243+
$this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
244+
$this->assertEquals($startdate, $c2->startdate);
245+
246+
// Now course c2 has two chats - one ('Second') was already there and one ('First') was restored from the backup.
247+
// Their dates are exactly the same as they were in the original modules.
248+
$restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
249+
$restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
250+
$this->assertEquals($chat1->chattime, $restoredchat1->chattime);
251+
$this->assertEquals($chat2->chattime, $restoredchat2->chattime);
252+
}
253+
254+
public function test_async_restore_course_info_in_existing_course_delete_first() {
255+
global $DB;
256+
$this->resetAfterTest();
257+
$dg = $this->getDataGenerator();
258+
259+
$this->assertEquals(1, get_config('restore', 'restore_merge_course_shortname'));
260+
$this->assertEquals(1, get_config('restore', 'restore_merge_course_fullname'));
261+
$this->assertEquals(1, get_config('restore', 'restore_merge_course_startdate'));
262+
263+
$startdate = mktime(12, 0, 0, 7, 1, 2016); // 01-Jul-2016.
264+
265+
// Create two courses with different start dates,in each course create a chat that opens 1 week after the course start date.
266+
$c1 = $dg->create_course(['shortname' => 'SN', 'fullname' => 'FN', 'summary' => 'DESC', 'summaryformat' => FORMAT_MOODLE,
267+
'startdate' => $startdate]);
268+
$chat1 = $dg->create_module('chat', ['name' => 'First', 'course' => $c1->id, 'chattime' => $c1->startdate + 1 * WEEKSECS]);
269+
$c2 = $dg->create_course(['shortname' => 'A', 'fullname' => 'B', 'summary' => 'C', 'summaryformat' => FORMAT_PLAIN,
270+
'startdate' => $startdate + 2 * WEEKSECS]);
271+
$chat2 = $dg->create_module('chat', ['name' => 'Second', 'course' => $c2->id, 'chattime' => $c2->startdate + 1 * WEEKSECS]);
272+
$backupid = $this->backup_course($c1->id);
273+
274+
// The information is restored and the existing course settings is modified.
275+
$c2 = $this->async_restore_to_existing_course($backupid, $c2->id, 2, backup::TARGET_CURRENT_DELETING);
276+
$this->assertEquals(FORMAT_MOODLE, $c2->summaryformat);
277+
278+
// Now course2 should have a new forum with the original forum deleted.
279+
$restoredchat1 = $DB->get_record('chat', ['name' => 'First', 'course' => $c2->id]);
280+
$restoredchat2 = $DB->get_record('chat', ['name' => 'Second', 'course' => $c2->id]);
281+
$this->assertEquals($chat1->chattime, $restoredchat1->chattime);
282+
$this->assertEmpty($restoredchat2);
283+
}
284+
134285
public function test_restore_existing_idnumber_in_new_course() {
135286
$this->resetAfterTest();
136287

0 commit comments

Comments
 (0)