From 414372072200c916b8f83f6539ac1f584eb89c2d Mon Sep 17 00:00:00 2001 From: Edmund Farrow Date: Fri, 8 Nov 2024 16:13:56 +0000 Subject: [PATCH] quiz-data - First pass at import whole course --- classes/cli_helper.php | 46 +----- classes/create_repo.php | 19 ++- classes/export_repo.php | 3 +- classes/export_trait.php | 6 - classes/import_repo.php | 38 ++--- cli/createwholecourserepo.php | 22 ++- cli/exportwholecoursefrommoodle.php | 21 ++- cli/importrepotomoodle.php | 8 + cli/importwholecoursetomoodle.php | 235 ++++++++++++++++++++++++++++ 9 files changed, 306 insertions(+), 92 deletions(-) create mode 100755 cli/importwholecoursetomoodle.php diff --git a/classes/cli_helper.php b/classes/cli_helper.php index 29c82d9..1cb56be 100644 --- a/classes/cli_helper.php +++ b/classes/cli_helper.php @@ -63,10 +63,6 @@ class cli_helper { * QUIZ_FILE - File name ending for quiz structure file. */ public const QUIZ_FILE = '_quiz.json'; - /** - * QUIZPATH_FILE - File name for quiz location file. - */ - public const QUIZPATH_FILE = 'quizlocation.json'; /** * TEMP_MANIFEST_FILE - File name ending for temporary manifest file. * Appended to name of moodle instance. @@ -445,19 +441,13 @@ public static function get_quiz_directory(string $basedirectory, string $quiznam * @param object $manifestcontents \stdClass Current contents of manifest file * @param string $tempfilepath * @param string $manifestpath - * @param string $moodleurl - * @param int|null $subcategoryid - * @param string|null $subdirectory * @param bool $showupdated - * @param object $activity * @return object */ - public static function create_manifest_file(object $manifestcontents, string $tempfilepath, - string $manifestpath, string $moodleurl, - ?int $subcategoryid=null, - ?string $subdirectory=null, - bool $showupdated=true, - object $activity=null):object { + public static function create_manifest_file(object $manifestcontents, + string $tempfilepath, + string $manifestpath, + bool $showupdated=true):object { // Read in temp file a question at a time, process and add to manifest. // No actual processing at the moment so could simplify to write straight // to manifest in the first place if no processing materialises. @@ -498,34 +488,8 @@ public static function create_manifest_file(object $manifestcontents, string $te $existingentries["{$questioninfo->questionbankentryid}"]->moodlecommit = $questioninfo->moodlecommit; } } - if ($manifestcontents->context === null) { - $manifestcontents->context = new \stdClass(); - $manifestcontents->context->contextlevel = $questioninfo->contextlevel; - $manifestcontents->context->coursename = $questioninfo->coursename; - $manifestcontents->context->modulename = $questioninfo->modulename; - $manifestcontents->context->coursecategory = $questioninfo->coursecategory; - $manifestcontents->context->instanceid = $questioninfo->instanceid; - $manifestcontents->context->defaultsubcategoryid = $subcategoryid; - $manifestcontents->context->defaultsubdirectory = $subdirectory; - $manifestcontents->context->defaultignorecat = $questioninfo->ignorecat; - $manifestcontents->context->moodleurl = $moodleurl; - } } } - // If there are no questions, we'll need to get context. - if ($manifestcontents->context === null) { - $context = $activity->cli_helper->check_context($activity, false, true); - $manifestcontents->context = new \stdClass(); - $manifestcontents->context->contextlevel = $questioninfo->contextlevel; - $manifestcontents->context->coursename = $questioninfo->coursename; - $manifestcontents->context->modulename = $questioninfo->modulename; - $manifestcontents->context->coursecategory = $questioninfo->coursecategory; - $manifestcontents->context->instanceid = $questioninfo->instanceid; - $manifestcontents->context->defaultsubcategoryid = $subcategoryid; - $manifestcontents->context->defaultsubdirectory = $subdirectory; - $manifestcontents->context->defaultignorecat = $questioninfo->ignorecat; - $manifestcontents->context->moodleurl = $moodleurl; - } echo "\nAdded {$addedcount} question" . (($addedcount !== 1) ? 's' : '') . ".\n"; if ($showupdated) { echo "Updated {$updatedcount} question" . (($updatedcount !== 1) ? 's' : '') . ".\n"; @@ -650,7 +614,7 @@ public function create_gitignore(string $manifestpath):void { $ignore = fopen($manifestdirname . '/.gitignore', 'a'); $contents = "**/*" . self::MANIFEST_FILE . "\n**/*" . - self::TEMP_MANIFEST_FILE . "\n**/" . self::QUIZPATH_FILE . "\n"; + self::TEMP_MANIFEST_FILE . "\n"; fwrite($ignore, $contents); fclose($ignore); } diff --git a/classes/create_repo.php b/classes/create_repo.php index 4f07cbc..4ddbdd6 100644 --- a/classes/create_repo.php +++ b/classes/create_repo.php @@ -197,6 +197,18 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) { $this->tempfilepath = str_replace(cli_helper::MANIFEST_FILE, '_export' . cli_helper::TEMP_MANIFEST_FILE, $this->manifestpath); + $this->manifestcontents = new \stdClass(); + $this->manifestcontents->context = new \stdClass(); + $this->manifestcontents->context->contextlevel = cli_helper::get_context_level($instanceinfo->contextinfo->contextlevel); + $this->manifestcontents->context->coursename = $instanceinfo->contextinfo->coursename; + $this->manifestcontents->context->modulename = $instanceinfo->contextinfo->modulename; + $this->manifestcontents->context->coursecategory = $instanceinfo->contextinfo->categoryname; + $this->manifestcontents->context->instanceid = $instanceinfo->contextinfo->instanceid; + $this->manifestcontents->context->defaultsubcategoryid = $this->qcategoryid; + $this->manifestcontents->context->defaultsubdirectory = null; + $this->manifestcontents->context->defaultignorecat = $this->ignorecat; + $this->manifestcontents->context->moodleurl = $this->moodleurl; + $this->manifestcontents->questions = []; } /** @@ -206,13 +218,10 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) { * @return void */ public function process():void { - $this->manifestcontents = new \stdClass(); - $this->manifestcontents->context = null; - $this->manifestcontents->questions = []; $this->export_to_repo(); + $this->manifestcontents->context->defaultsubdirectory = $this->subdirectory; cli_helper::create_manifest_file($this->manifestcontents, $this->tempfilepath, - $this->manifestpath, $this->moodleurl, - $this->qcategoryid, $this->subdirectory, false, $this); + $this->manifestpath, false); unlink($this->tempfilepath); } diff --git a/classes/export_repo.php b/classes/export_repo.php index 130061f..4565c91 100644 --- a/classes/export_repo.php +++ b/classes/export_repo.php @@ -192,8 +192,7 @@ public function process():void { // Export any questions that are in Moodle but not in the manifest. $this->export_to_repo(); cli_helper::create_manifest_file($this->manifestcontents, $this->tempfilepath, - $this->manifestpath, $this->moodleurl, - null, null, false, $this); + $this->manifestpath, false); unlink($this->tempfilepath); // Remove questions from manifest that are no longer in Moodle. // Will be restored from repo on next import if file is still there. diff --git a/classes/export_trait.php b/classes/export_trait.php index afee379..1474e28 100644 --- a/classes/export_trait.php +++ b/classes/export_trait.php @@ -202,14 +202,8 @@ public function export_to_repo_main_process(object $moodlequestionlist):void { $fileoutput = [ 'questionbankentryid' => $questioninfo->questionbankentryid, 'version' => $responsejson->version, - 'contextlevel' => $this->listpostsettings['contextlevel'], 'filepath' => str_replace( '\\', '/', $bottomdirectory) . "/{$sanitisedqname}.xml", - 'coursename' => $this->listpostsettings['coursename'], - 'modulename' => $this->listpostsettings['modulename'], - 'coursecategory' => $this->listpostsettings['coursecategory'], - 'instanceid' => $this->listpostsettings['instanceid'], 'format' => 'xml', - 'ignorecat' => $this->ignorecat, ]; fwrite($tempfile, json_encode($fileoutput) . "\n"); } diff --git a/classes/import_repo.php b/classes/import_repo.php index c2f0921..ce9ce2c 100644 --- a/classes/import_repo.php +++ b/classes/import_repo.php @@ -174,7 +174,7 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) { if ($arguments['directory']) { $this->directory = $arguments['rootdirectory'] . '/' . $arguments['directory']; } else { - if ($manifestpath) { + if ($manifestpath && dirname($manifestpath) !== '.') { $this->directory = $arguments['rootdirectory'] . '/' . dirname($manifestpath); } else { $this->directory = $arguments['rootdirectory']; @@ -290,7 +290,16 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) { $this->call_exit(); } else if (!$manifestcontents && !$manifestpath) { $this->manifestcontents = new \stdClass(); - $this->manifestcontents->context = null; + $this->manifestcontents->context = new \stdClass(); + $this->manifestcontents->context->contextlevel = cli_helper::get_context_level($instanceinfo->contextinfo->contextlevel); + $this->manifestcontents->context->coursename = $instanceinfo->contextinfo->coursename; + $this->manifestcontents->context->modulename = $instanceinfo->contextinfo->modulename; + $this->manifestcontents->context->coursecategory = $instanceinfo->contextinfo->categoryname; + $this->manifestcontents->context->instanceid = $instanceinfo->contextinfo->instanceid; + $this->manifestcontents->context->defaultsubcategoryid = $instanceinfo->contextinfo->qcategoryid; + $this->manifestcontents->context->defaultsubdirectory = $this->subdirectory; + $this->manifestcontents->context->defaultignorecat = $this->ignorecat; + $this->manifestcontents->context->moodleurl = $this->moodleurl; $this->manifestcontents->questions = []; } else { $this->manifestcontents = $manifestcontents; @@ -336,7 +345,9 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) { $this->listpostsettings['qcategoryname'] = $qcategoryname; $this->listcurlrequest->set_option(CURLOPT_POSTFIELDS, $this->listpostsettings); - if (count($this->manifestcontents->questions) === 0) { + if (count($this->manifestcontents->questions) === 0 && !$arguments['quiet']) { + // A quiz in a whole course set up can have an empty manifest as + // the questions may be in the course. echo "\nManifest file is empty. This should only be the case if you are importing "; echo "questions for the first time into a Moodle context where they don't already exist.\n"; $this->handle_abort(); @@ -352,15 +363,10 @@ public function __construct(cli_helper $clihelper, array $moodleinstances) { public function process():void { $this->import_categories(); $this->import_questions(); - $instanceinfo = $this->clihelper->check_context($this, true, true); $this->manifestcontents = cli_helper::create_manifest_file($this->manifestcontents, $this->tempfilepath, $this->manifestpath, - $this->moodleurl, - $instanceinfo->contextinfo->qcategoryid, - $this->subdirectory, - true, - $this); + true); unlink($this->tempfilepath); $this->delete_no_file_questions(false); $this->delete_no_record_questions(false); @@ -555,15 +561,8 @@ public function import_questions() { $fileoutput = [ 'questionbankentryid' => $responsejson->questionbankentryid, 'version' => $responsejson->version, - // Questions can be imported in multiple contexts. - 'contextlevel' => $this->postsettings['contextlevel'], 'filepath' => str_replace( '\\', '/', $repoitem->getPathname()), - 'coursename' => $this->postsettings['coursename'], - 'modulename' => $this->postsettings['modulename'], - 'coursecategory' => $this->postsettings['coursecategory'], - 'instanceid' => $this->postsettings['instanceid'], 'format' => 'xml', - 'ignorecat' => $this->ignorecat, ]; if ($existingentry && isset($existingentry->currentcommit)) { $fileoutput['moodlecommit'] = $existingentry->currentcommit; @@ -596,15 +595,10 @@ public function import_questions() { public function recovery():void { if (file_exists($this->tempfilepath)) { echo 'Attempting recovery from failure on previous run. Updating manifest:'; - $instanceinfo = $this->clihelper->check_context($this, true, true); $this->manifestcontents = cli_helper::create_manifest_file($this->manifestcontents, $this->tempfilepath, $this->manifestpath, - $this->moodleurl, - $instanceinfo->contextinfo->qcategoryid, - $this->subdirectory, - true, - $this); + true); unlink($this->tempfilepath); echo 'Recovery successful. Continuing...'; } diff --git a/cli/createwholecourserepo.php b/cli/createwholecourserepo.php index 9ba3aab..3420dba 100755 --- a/cli/createwholecourserepo.php +++ b/cli/createwholecourserepo.php @@ -165,28 +165,34 @@ $moodleinstance = $arguments['moodleinstance']; $coursemanifestname = cli_helper::get_manifest_path($moodleinstance, 'course', null, $contextinfo->contextinfo->coursename, null, $basedirectory); +$contentsjson = file_get_contents($coursemanifestname); +$manifestcontents = json_decode($contentsjson); + $instanceid = $arguments['instanceid']; $token = $arguments['token'][$moodleinstance]; $ignorecat = $arguments['ignorecat']; $ignorecat = ($ignorecat) ? ' -x "' . $ignorecat . '"' : ''; -$quizfilepath = $basedirectory . '/' . $clihelper::QUIZPATH_FILE; -$quiz_locations = []; +$quizlocations = []; foreach ($contextinfo->quizzes as $quiz) { - $instanceid = "{$quiz->instanceid}"; + $instanceid = $quiz->instanceid; $quizdirectory = cli_helper::get_quiz_directory($basedirectory, $quiz->name); $rootdirectory = $clihelper->create_directory($quizdirectory); echo "\nExporting quiz: {$quiz->name} to {$rootdirectory}\n"; chdir($scriptdirectory); - $output = shell_exec('php createrepo.php -r "' . $rootdirectory . '" -i "' . $moodleinstance . '" -l "module" -n ' . (int) $instanceid . ' -t ' . $token . ' -z' . $ignorecat); + $output = shell_exec('php createrepo.php -r "' . $rootdirectory . '" -i "' . $moodleinstance . '" -l "module" -n ' . $instanceid . ' -t ' . $token . ' -z' . $ignorecat); echo $output; $quizmanifestname = cli_helper::get_manifest_path($moodleinstance, 'module', null, $contextinfo->contextinfo->coursename, $quiz->name, $rootdirectory); chdir($scriptdirectory); - $output = shell_exec('php exportquizstructurefrommoodle.php -z -r "" -i "' . $moodleinstance . '" -n ' . (int) $instanceid . ' -t ' . $token. ' -p "' . $coursemanifestname. '" -f "' . $quizmanifestname . '"'); - $quiz_locations[$instanceid] = basename($rootdirectory); - $success = file_put_contents($quizfilepath, json_encode($quiz_locations)); + $output = shell_exec('php exportquizstructurefrommoodle.php -z -r "" -i "' . $moodleinstance . '" -n ' . $instanceid . ' -t ' . $token. ' -p "' . $coursemanifestname. '" -f "' . $quizmanifestname . '"'); + $quizlocation = new StdClass(); + $quizlocation->moduleid = $instanceid; + $quizlocation->directory = basename($rootdirectory); + $quizlocations[] = $quizlocation; + $manifestcontents->quizzes = $quizlocations; + $success = file_put_contents($coursemanifestname, json_encode($manifestcontents)); if ($success === false) { - echo "\nUnable to update quizpath file: {$quizfilepath}\n Aborting.\n"; + echo "\nUnable to update manifest file: {$coursemanifestname}\n Aborting.\n"; exit(); } echo $output; diff --git a/cli/exportwholecoursefrommoodle.php b/cli/exportwholecoursefrommoodle.php index 87655db..d6b6464 100644 --- a/cli/exportwholecoursefrommoodle.php +++ b/cli/exportwholecoursefrommoodle.php @@ -118,7 +118,7 @@ $exportrepo = new export_repo($clihelper, $moodleinstances); $clihelper->check_for_changes($exportrepo->manifestpath); $clihelper->backup_manifest($exportrepo->manifestpath); -// $exportrepo->process(); +$exportrepo->process(); // Create/update quiz directories and populate. $contextinfo = $clihelper->check_context($exportrepo, false, true); @@ -126,36 +126,41 @@ $moodleinstance = $arguments['moodleinstance']; $coursemanifestname = cli_helper::get_manifest_path($moodleinstance, 'course', null, $contextinfo->contextinfo->coursename, null, $basedirectory); +$contentsjson = file_get_contents($coursemanifestname); +$manifestcontents = json_decode($contentsjson); $token = $arguments['token'][$moodleinstance]; $ignorecat = $arguments['ignorecat']; $ignorecat = ($ignorecat) ? ' -x "' . $ignorecat . '"' : ''; -$quizfilepath = $basedirectory . '/' . $clihelper::QUIZPATH_FILE; $quizlocations = json_decode(file_get_contents($quizfilepath)); foreach ($contextinfo->quizzes as $quiz) { $instanceid = (int) $quiz->instanceid; if (!isset($quizlocations->$instanceid)) { $rootdirectory = $clihelper->create_directory(cli_helper::get_quiz_directory($basedirectory, $quiz->name)); - $quiz_locations[$instanceid] = basename($rootdirectory); - $success = file_put_contents($quizfilepath, json_encode($quiz_locations)); + $quizlocation = new \StdClass(); + $quizlocation->moduleid = $instanceid; + $quizlocation->directory = basename($rootdirectory); + $quizlocations[] = $quizlocation; + $manifestcontents->quizzes = $quizlocations; + $success = file_put_contents($coursemanifestname, json_encode($manifestcontents)); if ($success === false) { - echo "\nUnable to update quizpath file: {$quizfilepath}\n Aborting.\n"; + echo "\nUnable to update manifest file: {$coursemanifestname}\n Aborting.\n"; exit(); } echo "\nExporting quiz: {$quiz->name} to {$rootdirectory}\n"; chdir($scriptdirectory); - $output = shell_exec('php createrepo.php -r "' . $rootdirectory . '" -i "' . $moodleinstance . '" -l "module" -n ' . (int) $instanceid . ' -t ' . $token . ' -z' . $ignorecat); + $output = shell_exec('php createrepo.php -r "' . $rootdirectory . '" -i "' . $moodleinstance . '" -l "module" -n ' . $instanceid . ' -t ' . $token . ' -z' . $ignorecat); } else { $rootdirectory = dirname($basedirectory) . '/' . $quizlocations->$instanceid; echo "\nExporting quiz: {$quiz->name} to {$rootdirectory}\n"; chdir($scriptdirectory); $quizmanifestname = cli_helper::get_manifest_path($moodleinstance, 'module', null, $contextinfo->contextinfo->coursename, $quiz->name, ''); - $output = shell_exec('php exportrepofrommoodle.php -r "' . $rootdirectory . '" -i "' . $moodleinstance . '" -f "' . $quizmanifestname . '" -t ' . $token); + $output = shell_exec('php exportrepofrommoodle.php -z -r "' . $rootdirectory . '" -i "' . $moodleinstance . '" -f "' . $quizmanifestname . '" -t ' . $token); } echo $output; $quizmanifestname = cli_helper::get_manifest_path($moodleinstance, 'module', null, $contextinfo->contextinfo->coursename, $quiz->name, $rootdirectory); chdir($scriptdirectory); - $output = shell_exec('php exportquizstructurefrommoodle.php -z -r "" -i "' . $moodleinstance . '" -n ' . (int) $instanceid . ' -t ' . $token. ' -p "' . $coursemanifestname. '" -f "' . $quizmanifestname . '"'); + $output = shell_exec('php exportquizstructurefrommoodle.php -z -r "" -i "' . $moodleinstance . '" -n ' . $instanceid . ' -t ' . $token. ' -p "' . $coursemanifestname. '" -f "' . $quizmanifestname . '"'); echo $output; } diff --git a/cli/importrepotomoodle.php b/cli/importrepotomoodle.php index 0689909..2c179c3 100755 --- a/cli/importrepotomoodle.php +++ b/cli/importrepotomoodle.php @@ -145,6 +145,14 @@ 'variable' => 'ignorecat', 'valuerequired' => true, ], + [ + 'longopt' => 'quiet', + 'shortopt' => 'z', + 'description' => 'Do not display context info or option to abort.', + 'default' => false, + 'variable' => 'quiet', + 'valuerequired' => false, + ], ]; if (!function_exists('simplexml_load_file')) { diff --git a/cli/importwholecoursetomoodle.php b/cli/importwholecoursetomoodle.php new file mode 100755 index 0000000..d2b68a0 --- /dev/null +++ b/cli/importwholecoursetomoodle.php @@ -0,0 +1,235 @@ +. + +/** + * Import a git repo containing questions into Moodle. + * + * @package qbank_gitsync + * @copyright 2023 University of Edinburgh + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace qbank_gitsync; +define('CLI_SCRIPT', true); +require_once('./config.php'); +require_once('../classes/curl_request.php'); +require_once('../classes/cli_helper.php'); +require_once('../classes/tidy_trait.php'); +require_once('../classes/import_repo.php'); + +$options = [ + [ + 'longopt' => 'moodleinstance', + 'shortopt' => 'i', + 'description' => 'Key of Moodle instance in $moodleinstances to use. ' . + 'Should match end of instance URL.', + 'default' => $instance, + 'variable' => 'moodleinstance', + 'valuerequired' => true, + ], + [ + 'longopt' => 'rootdirectory', + 'shortopt' => 'r', + 'description' => "Directory on user's computer containing repos.", + 'default' => $rootdirectory, + 'variable' => 'rootdirectory', + 'valuerequired' => true, + ], + [ + 'longopt' => 'manifestpath', + 'shortopt' => 'f', + 'description' => 'Filepath of manifest file relative to root directory.', + 'default' => $manifestpath, + 'variable' => 'manifestpath', + 'valuerequired' => true, + ], + [ + 'longopt' => 'directory', + 'shortopt' => 'd', + 'description' => 'Directory of repo on users computer containing "top" folder, ' . + 'relative to root directory.', + 'default' => '', + 'variable' => 'directory', + 'valuerequired' => true, + ], + [ + 'longopt' => 'subdirectory', + 'shortopt' => 's', + 'description' => 'Relative subdirectory of repo to actually import.', + 'default' => null, + 'variable' => 'subdirectory', + 'valuerequired' => true, + ], + [ + 'longopt' => 'contextlevel', + 'shortopt' => 'l', + 'description' => 'Context in which to place questions. Set to system, coursecategory, course or module', + 'default' => null, + 'variable' => 'contextlevel', + 'valuerequired' => true, + ], + [ + 'longopt' => 'coursename', + 'shortopt' => 'c', + 'description' => 'Unique course name for course or module context.', + 'default' => null, + 'variable' => 'coursename', + 'valuerequired' => true, + ], + [ + 'longopt' => 'modulename', + 'shortopt' => 'm', + 'description' => 'Unique (within course) module name for module context.', + 'default' => null, + 'variable' => 'modulename', + 'valuerequired' => true, + ], + [ + 'longopt' => 'coursecategory', + 'shortopt' => 'g', + 'description' => 'Unique course category name for coursecategory context.', + 'default' => null, + 'variable' => 'coursecategory', + 'valuerequired' => true, + ], + [ + 'longopt' => 'instanceid', + 'shortopt' => 'n', + 'description' => 'Numerical id of the course, module of course category.', + 'default' => null, + 'variable' => 'instanceid', + 'valuerequired' => true, + ], + [ + 'longopt' => 'token', + 'shortopt' => 't', + 'description' => 'Security token for webservice.', + 'default' => $token, + 'variable' => 'token', + 'valuerequired' => true, + ], + [ + 'longopt' => 'help', + 'shortopt' => 'h', + 'description' => '', + 'default' => false, + 'variable' => 'help', + 'valuerequired' => false, + ], + [ + 'longopt' => 'usegit', + 'shortopt' => 'u', + 'description' => 'Is the repo controlled using Git?', + 'default' => $usegit, + 'variable' => 'usegit', + 'valuerequired' => false, + ], + [ + 'longopt' => 'ignorecat', + 'shortopt' => 'x', + 'description' => 'Regex of categories to ignore - add an extra leading / for Windows.', + 'default' => $ignorecat, + 'variable' => 'ignorecat', + 'valuerequired' => true, + ], +]; + +if (!function_exists('simplexml_load_file')) { + echo 'Please install the PHP library SimpleXML.' . "\n"; + exit; +} + +$scriptdirectory = dirname(__FILE__); +$clihelper = new cli_helper($options); +$arguments = $clihelper->get_arguments(); +echo "Importing a course into Moodle. Associated quiz contexts will also be imported.\n"; +echo "Structures of existing quizzes in Moodle will not be updated.\n"; +$importrepo = new import_repo($clihelper, $moodleinstances); +$clihelper->check_for_changes($importrepo->manifestpath); +$clihelper->backup_manifest($importrepo->manifestpath); +$importrepo->recovery(); +$importrepo->check_question_versions(); +$clihelper->commit_hash_update($importrepo); +$importrepo->process(); + +// Create/update quiz questions. +$contextinfo = $clihelper->check_context($importrepo, false, true); +$basedirectory = dirname($importrepo->manifestpath); +$moodleinstance = $arguments['moodleinstance']; +$coursemanifestname = cli_helper::get_manifest_path($moodleinstance, 'course', null, + $contextinfo->contextinfo->coursename, null, $basedirectory); +$contentsjson = file_get_contents($coursemanifestname); +$manifestcontents = json_decode($contentsjson); +$token = $arguments['token'][$moodleinstance]; +$ignorecat = $arguments['ignorecat']; +$ignorecat = ($ignorecat) ? ' -x "' . $ignorecat . '"' : ''; +$quizlocations = $manifestcontents->quizzes; +$topdircontents = scandir(dirname($basedirectory)); +foreach ($topdircontents as $quizdirectory) { + if (!is_dir(dirname($basedirectory) . '/' . $quizdirectory) || strpos($quizdirectory, '_quiz_') === false) { + continue; + } + $instanceid = array_column($quizlocations, null, 'directory')[$quizdirectory]->moduleid ?? false; + $rootdirectory = dirname($basedirectory) . '/' . $quizdirectory; + $quizfiles = scandir($rootdirectory); + $structurefile = null; + foreach($quizfiles as $quizfile) { + if (preg_match('/.*_quiz\.json/', $quizfile)) { + $structurefile = $quizfile; + break; + } + } + $structurefile = $rootdirectory . '/' . $structurefile; + $contentsjson = file_get_contents($structurefile); + $structurecontents = json_decode($contentsjson); + chdir($scriptdirectory); + $quizmanifestname = cli_helper::get_manifest_path($moodleinstance, 'module', null, + $contextinfo->contextinfo->coursename, $structurecontents->quiz->name, ''); + if (is_dir($rootdirectory . '/top')) { + // Quiz could have no questions in its context. + echo "\nImporting quiz context: {$structurecontents->quiz->name}\n"; + $output = shell_exec('php importrepotomoodle.php -z -r "' . $rootdirectory . + '" -i "' . $moodleinstance . '" -f "' . $quizmanifestname . '" -t ' . $token); + echo $output; + } + if ($instanceid === false) { + chdir($scriptdirectory); + echo "\nImporting quiz structure: {$structurecontents->quiz->name}\n"; + $output = shell_exec('php importquizstructuretomoodle.php -z -r "" -i "' . $moodleinstance . '" -n ' . + $contextinfo->contextinfo->instanceid . ' -t ' . $token. ' -p "' . + $coursemanifestname. '" -f "' . $quizmanifestname . '" -a "' . $structurefile . '"'); + echo $output; + $quizlocation = new \StdClass(); + $quizlocation->moduleid = $instanceid; + $quizlocation->directory = basename($rootdirectory); + $quizlocations[] = $quizlocation; + $manifestcontents->quizzes = $quizlocations; + $success = file_put_contents($coursemanifestname, json_encode($manifestcontents)); + if ($success === false) { + echo "\nUnable to update manifest file: {$coursemanifestname}\n Aborting.\n"; + exit(); + } + } +} + +$quizlocations = $manifestcontents->quizzes; +$locarray = array_column($quizlocations, null, 'moduleid'); +foreach ($contextinfo->quizzes as $quiz) { + $instanceid = (int) $quiz->instanceid; + if (!isset($locarray[$instanceid])) { + echo "\nQuiz {$quiz->name} should be exported from Moodle or deleted.\n"; + } +}