From 9fae3549f108ef7120a9facbf5c13ae9c55efda6 Mon Sep 17 00:00:00 2001 From: Kumi Date: Mon, 22 Aug 2022 09:52:55 +0000 Subject: [PATCH] Status quo --- import.php | 136 ++++++++++++++++++++++++++++++++++ import_cli.php | 194 +++++++++++++++++++++++++++++++++++++++++++++++++ trigger.php | 43 +++++++---- 3 files changed, 360 insertions(+), 13 deletions(-) create mode 100644 import.php create mode 100644 import_cli.php diff --git a/import.php b/import.php new file mode 100644 index 0000000..fb9e409 --- /dev/null +++ b/import.php @@ -0,0 +1,136 @@ +dirroot . '/backup/util/includes/backup_includes.php'); +require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php"); + +$courseid = $_GET["courseid"]; +$categoryid = $_GET["categoryid"]; +$timestamp = $_GET["timestamp"]; + +try { + $course = get_course($courseid); +} catch (Exception $ex) { + $course = null; +} + +if (!$course) { + if (!get_course(((int) $courseid) - 1)) { + die("Cannot recreate course with this ID!"); + } +} + +if ($course && !$categoryid) { + $categoryid = $course->category; +} + +$category = $DB->get_record('course_categories', array('id' => $categoryid), '*', MUST_EXIST); + +$replicationconfig = get_config('local_replication'); +$directory = $replicationconfig->directory; + +$infile = $directory . DIRECTORY_SEPARATOR . "course_" . $courseid . "_" . $categoryid . "_" . $timestamp . ".mbz"; + +if (empty($CFG->tempdir)) { + $CFG->tempdir = $CFG->dataroot . DIRECTORY_SEPARATOR . 'temp'; +} + +if (!file_exists($infile)) { + die("Backup file '" . $infile . "' does not exist."); +} + +if (!is_readable($infile)) { + die("Backup file '" . $infile . "' is not readable."); +} + +$backupdir = "restore_" . uniqid(); + +if (isset($CFG->backuptempdir)){ + $path = $CFG->backuptempdir . DIRECTORY_SEPARATOR . $backupdir; +} +else{ + $path = $CFG->tempdir . DIRECTORY_SEPARATOR . "backup" . DIRECTORY_SEPARATOR . $backupdir; +} + +$fp = get_file_packer('application/vnd.moodle.backup'); +$fp->extract_to_pathname($infile, $path); + +$xmlfile = $path . DIRECTORY_SEPARATOR . "course" . DIRECTORY_SEPARATOR . "course.xml"; + +$xml = simplexml_load_file($xmlfile); +$fullname = $xml->xpath('/course/fullname'); +if (!$fullname) { + $fullname = $xml->xpath('/MOODLE_BACKUP/COURSE/HEADER/FULLNAME'); +} +$shortname = $xml->xpath('/course/shortname'); +if (!$shortname) { + $shortname = $xml->xpath('/MOODLE_BACKUP/COURSE/HEADER/SHORTNAME'); +} + +$fullname = (string)($fullname[0]); +$shortname = (string)($shortname[0]); + +if (!$fullname) { + $fullname = $shortname; +} + +if (!$course && $DB->get_record('course', array('category' => $category->id, 'shortname' => $shortname))) { + $matches = NULL; + preg_match('/(.*)_(\d+)$/', $shortname, $matches); + if ($matches) { + $base = $matches[1]; + $number = $matches[2]; + } else { + $base = $shortname; + $number = 1; + } + $shortname = $base . '_' . $number; + while ($DB->get_record('course', array('category' => $category->id, 'shortname' => $shortname))) { + $number++; + $shortname = $base . '_' . $number; + } +} + +if ($course) { + echo "Overwriting current content of existing course -> Course ID: $courseid\n"; + $rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO, + backup::MODE_GENERAL, $USER->id, 0); +} else { + echo "Creating new course to restore backup\n"; + $courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id); + $rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO, + backup::MODE_GENERAL, $USER->id, backup::TARGET_NEW_COURSE); +} + +if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) { + $rc->convert(); +} + +$plan = $rc->get_plan(); + +if (!$rc->execute_precheck()){ + $check = $rc->get_precheck_results(); + echo("Restore pre-check failed!"); + var_dump($check); + die(); +} + +$deletingoptions = array(); +$deletingoptions['keep_roles_and_enrolments'] = 1; +$deletingoptions['keep_groups_and_groupings'] = 1; +restore_dbops::delete_course_content($courseid, $deletingoptions); + +$rc->execute_plan(); +$rc->destroy(); + +#unlink($infile); + +$course = get_course($courseid); + +$course->category = $categoryid; +$course->fullname = $fullname; +$course->shortname = $shortname; + +$DB->update_record('course', $course); + +echo "New course ID for '$shortname': $courseid in category {$category->id}\n"; +echo "OK" diff --git a/import_cli.php b/import_cli.php new file mode 100644 index 0000000..64279f7 --- /dev/null +++ b/import_cli.php @@ -0,0 +1,194 @@ +dirroot . '/backup/util/includes/backup_includes.php'); +require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php"); +require_once($CFG->libdir . '/clilib.php'); + +$usage = "Import a course from ContentMonster + +Usage: + # php import_cli.php --courseid= --categoryid= --timestamp= [--source=] + # php import_cli.php [--help|-h] + +Options: + -h --help Print this help. + --paramname= Describe the parameter and the meaning of its values. +"; + +list($options, $unrecognised) = cli_get_params([ + 'help' => false, + 'courseid' => null, + 'categoryid' => null, + 'timestamp' => null, + 'source' => null, +], [ + 'h' => 'help' +]); + +if ($unrecognised) { + $unrecognised = implode(PHP_EOL . ' ', $unrecognised); + cli_error(get_string('cliunknowoption', 'core_admin', $unrecognised)); +} + +if ($options['help']) { + cli_writeln($usage); + exit(2); +} + +if (empty($options['courseid'])) { + cli_error('Missing mandatory argument courseid.', 2); +} + +if (empty($options['categoryid'])) { + cli_error('Missing mandatory argument categoryid.', 2); +} + +if (empty($options['timestamp'])) { + cli_error('Missing mandatory argument timestamp.', 2); +} + +function generateRandomString($length = 10) { + $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $charactersLength = strlen($characters); + $randomString = ''; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[rand(0, $charactersLength - 1)]; + } + return $randomString; +} + + +$courseid = $options['courseid']; +$categoryid = $options["categoryid"]; +$timestamp = $options["timestamp"]; + +try { + $course = get_course($courseid); +} catch (Exception $ex) { + $course = null; +} + +try { + $category = $DB->get_record('course_categories', array('id' => $categoryid), '*', MUST_EXIST); +} catch (Exception $ex) { + cli_error('Category " . $categoryid . " does not exist.'); +} + +if (!$course) { + while (!get_course(((int) $courseid) - 1)) { + $name = generateRandomString(); + $newcourse = restore_dbops::create_new_course("Placeholder " . $name, $name, $category->id); + if ((int) $newcourse > (int) $courseid) { + cli_error('Did you delete courses by any chance? Cannot create course ' . $courseid . '.'); + } + } +} + +$replicationconfig = get_config('local_replication'); +$directory = $replicationconfig->directory; + +$infile = $directory . DIRECTORY_SEPARATOR . "course_" . $courseid . "_" . $categoryid . "_" . $timestamp . ".mbz"; + +if (empty($CFG->tempdir)) { + $CFG->tempdir = $CFG->dataroot . DIRECTORY_SEPARATOR . 'temp'; +} + +if (!file_exists($infile)) { + cli_error("Backup file '" . $infile . "' does not exist."); +} + +if (!is_readable($infile)) { + cli_error("Backup file '" . $infile . "' is not readable."); +} + +$backupdir = "restore_" . uniqid(); + +if (isset($CFG->backuptempdir)){ + $path = $CFG->backuptempdir . DIRECTORY_SEPARATOR . $backupdir; +} +else{ + $path = $CFG->tempdir . DIRECTORY_SEPARATOR . "backup" . DIRECTORY_SEPARATOR . $backupdir; +} + +$fp = get_file_packer('application/vnd.moodle.backup'); +$fp->extract_to_pathname($infile, $path); + +$xmlfile = $path . DIRECTORY_SEPARATOR . "course" . DIRECTORY_SEPARATOR . "course.xml"; + +$xml = simplexml_load_file($xmlfile); +$fullname = $xml->xpath('/course/fullname'); +if (!$fullname) { + $fullname = $xml->xpath('/MOODLE_BACKUP/COURSE/HEADER/FULLNAME'); +} +$shortname = $xml->xpath('/course/shortname'); +if (!$shortname) { + $shortname = $xml->xpath('/MOODLE_BACKUP/COURSE/HEADER/SHORTNAME'); +} + +$fullname = (string)($fullname[0]); +$shortname = (string)($shortname[0]); + +if (!$fullname) { + $fullname = $shortname; +} + +if (!$course && $DB->get_record('course', array('category' => $category->id, 'shortname' => $shortname))) { + $matches = NULL; + preg_match('/(.*)_(\d+)$/', $shortname, $matches); + if ($matches) { + $base = $matches[1]; + $number = $matches[2]; + } else { + $base = $shortname; + $number = 1; + } + $shortname = $base . '_' . $number; + while ($DB->get_record('course', array('category' => $category->id, 'shortname' => $shortname))) { + $number++; + $shortname = $base . '_' . $number; + } +} + +if ($course) { + cli_writeln("Overwriting current content of existing course -> Course ID: $courseid"); + $rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO, + backup::MODE_GENERAL, 2, 0); +} else { + cli_writeln("Creating new course to restore backup"); + $courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id); + $rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO, + backup::MODE_GENERAL, 2, backup::TARGET_NEW_COURSE); +} + +if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) { + $rc->convert(); +} + +$plan = $rc->get_plan(); + +if (!$rc->execute_precheck()){ + $check = $rc->get_precheck_results(); + cli_error("Restore pre-check failed!"); +} + +$deletingoptions = array(); +$deletingoptions['keep_roles_and_enrolments'] = 1; +$deletingoptions['keep_groups_and_groupings'] = 1; +restore_dbops::delete_course_content($courseid, $deletingoptions); + +$rc->execute_plan(); +$rc->destroy(); + +#unlink($infile); + +$course = get_course($courseid); + +$course->category = $categoryid; +$course->fullname = $fullname; +$course->shortname = $shortname; + +$DB->update_record('course', $course); + +cli_writeln("New course ID for '$shortname': $courseid in category {$category->id}"); +cli_writeln("OK"); diff --git a/trigger.php b/trigger.php index 979d54d..dda93de 100644 --- a/trigger.php +++ b/trigger.php @@ -1,13 +1,6 @@ dirroot . '/backup/util/includes/backup_includes.php'); $id = $_GET["id"]; $course = get_course($id); @@ -15,14 +8,38 @@ $course = get_course($id); $replicationconfig = get_config('local_replication'); $directory = $replicationconfig->directory; -if (!str_ends_with($directory, "/")) $directory = $directory . "/"; - $context = context_course::instance($id); if (!has_capability('local/replication:replicate', $context)) { die("User not allowed to trigger replication!"); } -if (!touch($directory . $id . "-" . $course->category . ".mew")) { - die("Could not touch $directory$id-{$course->category}.mew"); -} \ No newline at end of file +$bc = new backup_controller(\backup::TYPE_1COURSE, $id, backup::FORMAT_MOODLE, + backup::INTERACTIVE_YES, backup::MODE_GENERAL, $USER->id); + +$tasks = $bc->get_plan()->get_tasks(); +foreach ($tasks as &$task) { + if ($task instanceof \backup_root_task) { + $setting = $task->get_setting('users'); + $setting->set_value('0'); + $setting = $task->get_setting('anonymize'); + $setting->set_value('1'); + $setting = $task->get_setting('role_assignments'); + $setting->set_value('0'); + $setting = $task->get_setting('filters'); + $setting->set_value('0'); + $setting = $task->get_setting('comments'); + $setting->set_value('0'); + $setting = $task->get_setting('logs'); + $setting->set_value('0'); + $setting = $task->get_setting('grade_histories'); + $setting->set_value('0'); + } +} + +$filename = $directory . '/course_' . $id . "_" . $course->category . "_" . date('U') . '.mbz'; + +$bc->set_status(backup::STATUS_AWAITING); +$bc->execute_plan(); + +echo('Course is now getting replicated. Back to Course Administration');