Skip to content

Commit

Permalink
quiz-data - First pass at whole course export
Browse files Browse the repository at this point in the history
  • Loading branch information
EJMFarrow committed Nov 7, 2024
1 parent 66d0fdf commit b4434b8
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 9 deletions.
26 changes: 24 additions & 2 deletions classes/cli_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ 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.
Expand Down Expand Up @@ -445,13 +449,15 @@ public static function get_quiz_directory(string $basedirectory, string $quiznam
* @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 {
bool $showupdated=true,
object $activity=null):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.
Expand Down Expand Up @@ -506,6 +512,20 @@ public static function create_manifest_file(object $manifestcontents, string $te
}
}
}
// 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";
Expand Down Expand Up @@ -628,7 +648,9 @@ public function create_gitignore(string $manifestpath):void {
$manifestdirname = dirname($manifestpath);
if (!is_file($manifestdirname . '/.gitignore')) {
$ignore = fopen($manifestdirname . '/.gitignore', 'a');
$contents = "**/*_question_manifest.json\n**/*_manifest_update.tmp\n";

$contents = "**/*" . self::MANIFEST_FILE . "\n**/*" .
self::TEMP_MANIFEST_FILE . "\n**/" . self::QUIZPATH_FILE . "\n";
fwrite($ignore, $contents);
fclose($ignore);
}
Expand Down
2 changes: 1 addition & 1 deletion classes/create_repo.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public function process():void {
$this->export_to_repo();
cli_helper::create_manifest_file($this->manifestcontents, $this->tempfilepath,
$this->manifestpath, $this->moodleurl,
$this->qcategoryid, $this->subdirectory, false);
$this->qcategoryid, $this->subdirectory, false, $this);
unlink($this->tempfilepath);
}

Expand Down
2 changes: 1 addition & 1 deletion classes/export_repo.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public function process():void {
$this->export_to_repo();
cli_helper::create_manifest_file($this->manifestcontents, $this->tempfilepath,
$this->manifestpath, $this->moodleurl,
null, null, false);
null, null, false, $this);
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.
Expand Down
8 changes: 6 additions & 2 deletions classes/import_repo.php
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@ public function process():void {
$this->manifestpath,
$this->moodleurl,
$instanceinfo->contextinfo->qcategoryid,
$this->subdirectory);
$this->subdirectory,
true,
$this);
unlink($this->tempfilepath);
$this->delete_no_file_questions(false);
$this->delete_no_record_questions(false);
Expand Down Expand Up @@ -600,7 +602,9 @@ public function recovery():void {
$this->manifestpath,
$this->moodleurl,
$instanceinfo->contextinfo->qcategoryid,
$this->subdirectory);
$this->subdirectory,
true,
$this);
unlink($this->tempfilepath);
echo 'Recovery successful. Continuing...';
}
Expand Down
17 changes: 14 additions & 3 deletions cli/createmultiplerepos.php → cli/createwholecourserepo.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
*/

namespace qbank_gitsync;

use stdClass;
define('CLI_SCRIPT', true);
require_once('./config.php');
require_once('../classes/curl_request.php');
Expand Down Expand Up @@ -140,7 +142,7 @@
exit;
}

// Create course repo.
// Create course directory and populate.
$scriptdirectory = dirname(__FILE__);
$clihelper = new cli_helper($options);
$arguments = $clihelper->get_arguments();
Expand All @@ -153,7 +155,7 @@
$createrepo->process();
$clihelper->commit_hash_setup($createrepo);

// Create quiz repos.
// Create quiz directories and populate.
$contextinfo = $clihelper->check_context($createrepo, false, true);
if ($arguments['directory']) {
$basedirectory = $arguments['rootdirectory'] . '/' . $arguments['directory'];
Expand All @@ -167,9 +169,12 @@
$token = $arguments['token'][$moodleinstance];
$ignorecat = $arguments['ignorecat'];
$ignorecat = ($ignorecat) ? ' -x "' . $ignorecat . '"' : '';
$quizfilepath = $basedirectory . '/' . $clihelper::QUIZPATH_FILE;
$quiz_locations = [];
foreach ($contextinfo->quizzes as $quiz) {
$instanceid = "{$quiz->instanceid}";
$rootdirectory = $clihelper->create_directory(cli_helper::get_quiz_directory($basedirectory, $quiz->name));
$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);
Expand All @@ -178,6 +183,12 @@
$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));
if ($success === false) {
echo "\nUnable to update quizpath file: {$quizfilepath}\n Aborting.\n";
exit();
}
echo $output;
}
// Commit the final quiz file.
Expand Down
8 changes: 8 additions & 0 deletions cli/exportrepofrommoodle.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,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')) {
Expand Down
161 changes: 161 additions & 0 deletions cli/exportwholecoursefrommoodle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<?php
// This file is part of Stack - http://stack.maths.ed.ac.uk/
//
// Stack is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Stack is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Stack. If not, see <http://www.gnu.org/licenses/>.

/**
* Export from Moodle into a git repo containing questions.
*
* @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/export_trait.php');
require_once('../classes/tidy_trait.php');
require_once('../classes/export_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' => 'subcategory',
'shortopt' => 's',
'description' => 'Relative subcategory of question to actually export.',
'default' => null,
'variable' => 'subcategory',
'valuerequired' => true,
],
[
'longopt' => 'questioncategoryid',
'shortopt' => 'q',
'description' => 'Numerical id of subcategory to actually export.',
'default' => null,
'variable' => 'qcategoryid',
'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 "Exporting a course. Associated quiz contexts will also be exported.\n";
$exportrepo = new export_repo($clihelper, $moodleinstances);
$clihelper->check_for_changes($exportrepo->manifestpath);
$clihelper->backup_manifest($exportrepo->manifestpath);
// $exportrepo->process();

// Create/update quiz directories and populate.
$contextinfo = $clihelper->check_context($exportrepo, false, true);
$basedirectory = dirname($exportrepo->manifestpath);
$moodleinstance = $arguments['moodleinstance'];
$coursemanifestname = cli_helper::get_manifest_path($moodleinstance, 'course', null,
$contextinfo->contextinfo->coursename, null, $basedirectory);
$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));
if ($success === false) {
echo "\nUnable to update quizpath file: {$quizfilepath}\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);
} 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);
}
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 . '"');
echo $output;
}

0 comments on commit b4434b8

Please sign in to comment.