Skip to content
Snippets Groups Projects
Commit fb6fa2c5 authored by Alexander Loewe's avatar Alexander Loewe
Browse files

Added support to import and export textarea specific options and taskfiles

parent a18436ba
No related branches found
No related tags found
No related merge requests found
...@@ -82,7 +82,7 @@ class qtype_moopt_external extends external_api { ...@@ -82,7 +82,7 @@ class qtype_moopt_external extends external_api {
$usercontext = context_user::instance($USER->id); $usercontext = context_user::instance($USER->id);
self::validate_context($usercontext); self::validate_context($usercontext);
$unzipinfo = unzip_task_file_in_draft_area($draftid, $usercontext); $unzipinfo = unzip_task_file_in_file_area($usercontext, 'user', 'draft', $draftid);
if ($unzipinfo == null) { if ($unzipinfo == null) {
return ['error' => 'Error extracting zip file']; return ['error' => 'Error extracting zip file'];
} else if (isset($unzipinfo['error'])) { } else if (isset($unzipinfo['error'])) {
...@@ -92,7 +92,7 @@ class qtype_moopt_external extends external_api { ...@@ -92,7 +92,7 @@ class qtype_moopt_external extends external_api {
$taskzipfilename = $unzipinfo['zip'] ?? null; $taskzipfilename = $unzipinfo['zip'] ?? null;
$keepfilename = $taskzipfilename != null ? $taskzipfilename : $taskxmlfilename; $keepfilename = $taskzipfilename != null ? $taskzipfilename : $taskxmlfilename;
$doc = create_domdocument_from_task_xml($usercontext, $draftid, $taskxmlfilename, $taskzipfilename); $doc = create_domdocument_from_task_xml($usercontext, 'user', 'draft', $draftid, $taskxmlfilename, $taskzipfilename);
$namespace = detect_proforma_namespace($doc); $namespace = detect_proforma_namespace($doc);
$returnval = array(); $returnval = array();
...@@ -290,7 +290,7 @@ class qtype_moopt_external extends external_api { ...@@ -290,7 +290,7 @@ class qtype_moopt_external extends external_api {
} }
// Do a little bit of cleanup and remove everything from the file area we extracted. // Do a little bit of cleanup and remove everything from the file area we extracted.
remove_all_files_from_draft_area($draftid, $usercontext, $keepfilename); remove_all_files_from_file_area($usercontext, 'user', 'draft', $draftid, $keepfilename);
return $returnval; return $returnval;
} }
......
...@@ -118,41 +118,43 @@ use qtype_moopt\exceptions\resource_not_found_exception; ...@@ -118,41 +118,43 @@ use qtype_moopt\exceptions\resource_not_found_exception;
use qtype_moopt\utility\communicator\communicator_factory; use qtype_moopt\utility\communicator\communicator_factory;
use qtype_moopt\utility\proforma_xml\separate_feedback_handler; use qtype_moopt\utility\proforma_xml\separate_feedback_handler;
/* /**
* Unzips the task zip file in the given draft area into the area * Unzips the task zip file in the given file area into the area
* moodle doesn't display thrown exceptions, so we handle them as array with key 'error' in calling function * moodle doesn't display thrown exceptions, so we handle them as array with key 'error' in calling function
* *
* @param type $draftareaid * @param type $context
* @param type $usercontext * @param type $component
* @param type $filearea
* @param type $fileareaid
* @return array the name of the task zip file and the task xml file. * @return array the name of the task zip file and the task xml file.
* [ * [
* 'zip' => (string) the name of the zip file, if any (the key 'zip' is optional) * 'zip' => (string) the name of the zip file, if any (the key 'zip' is optional)
* 'xml' => (string) the name of the xml file (mandatory) * 'xml' => (string) the name of the xml file (mandatory)
* ] * ]
* Returns false, if there is no file in the given draft area. * Returns false, if there is no file in the given file area.
*/ */
function unzip_task_file_in_draft_area($draftareaid, $usercontext) { function unzip_task_file_in_file_area($context, $component, $filearea, $fileareaid) {
global $USER; global $USER;
$fs = get_file_storage(); $fs = get_file_storage();
// Check if there is only the file we want. // Check if there is only the file we want.
$area = file_get_draft_area_info($draftareaid, "/"); $area = file_get_file_area_info($context->id, $component, $filearea, $fileareaid, "/");
if ($area['filecount'] == 0) { if ($area['filecount'] == 0) {
return false; return false;
} else if ($area['filecount'] > 1 || $area['foldercount'] != 0) { } else if ($area['filecount'] > 1 || $area['foldercount'] != 0) {
$error = 'Only one file is allowed to be in this draft area: A ProFormA-Task as either ZIP or XML file. Check for additional folders as well.'; $error = 'Only one file is allowed to be in this file area: A ProFormA-Task as either ZIP or XML file. Check for additional folders as well.';
return array('error' => $error); return array('error' => $error);
} }
// Get name of the file. // Get name of the file.
$files = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftareaid); $files = $fs->get_area_files($context->id, $component, $filearea, $fileareaid);
// Get_area_files returns an associative array where the keys are some kind of hash value. // Get_area_files returns an associative array where the keys are some kind of hash value.
$keys = array_keys($files); $keys = array_keys($files);
// Index 1 because index 0 is the current directory it seems. // Index 1 because index 0 is the current directory it seems.
$filename = $files[$keys[1]]->get_filename(); $filename = $files[$keys[1]]->get_filename();
$file = $fs->get_file($usercontext->id, 'user', 'draft', $draftareaid, "/", $filename); $file = $fs->get_file($context->id, $component, $filearea, $fileareaid, "/", $filename);
// Check file type (it's really only checking the file extension but that is good enough here). // Check file type (it's really only checking the file extension but that is good enough here).
$fileinfo = pathinfo($filename); $fileinfo = pathinfo($filename);
...@@ -174,13 +176,13 @@ function unzip_task_file_in_draft_area($draftareaid, $usercontext) { ...@@ -174,13 +176,13 @@ function unzip_task_file_in_draft_area($draftareaid, $usercontext) {
$zipper = get_file_packer('application/zip'); $zipper = get_file_packer('application/zip');
// Find unused name for directory to extract the archive. // Find unused name for directory to extract the archive.
$temppath = $fs->get_unused_dirname($usercontext->id, 'user', 'draft', $draftareaid, "/" . pathinfo($zipfilename, $temppath = $fs->get_unused_dirname($context->id, $component, $filearea, $fileareaid, "/" . pathinfo($zipfilename,
PATHINFO_FILENAME) . '/'); PATHINFO_FILENAME) . '/');
$donotremovedirs = array(); $donotremovedirs = array();
$doremovedirs = array($temppath); $doremovedirs = array($temppath);
// Extract archive and move all files from $temppath to $filepath. // Extract archive and move all files from $temppath to $filepath.
if ($file->extract_to_storage($zipper, $usercontext->id, 'user', 'draft', $draftareaid, $temppath, $USER->id)) { if ($file->extract_to_storage($zipper, $context->id, $component, $filearea, $fileareaid, $temppath, $USER->id)) {
$extractedfiles = $fs->get_directory_files($usercontext->id, 'user', 'draft', $draftareaid, $temppath, true); $extractedfiles = $fs->get_directory_files($context->id, $component, $filearea, $fileareaid, $temppath, true);
$xtemppath = preg_quote($temppath, '|'); $xtemppath = preg_quote($temppath, '|');
foreach ($extractedfiles as $exfile) { foreach ($extractedfiles as $exfile) {
$realpath = preg_replace('|^' . $xtemppath . '|', '/', $exfile->get_filepath()); $realpath = preg_replace('|^' . $xtemppath . '|', '/', $exfile->get_filepath());
...@@ -188,13 +190,18 @@ function unzip_task_file_in_draft_area($draftareaid, $usercontext) { ...@@ -188,13 +190,18 @@ function unzip_task_file_in_draft_area($draftareaid, $usercontext) {
// Set the source to the extracted file to indicate that it came from archive. // Set the source to the extracted file to indicate that it came from archive.
$exfile->set_source(serialize((object)array('source' => '/'))); $exfile->set_source(serialize((object)array('source' => '/')));
} }
if (!$fs->file_exists($usercontext->id, 'user', 'draft', $draftareaid, $realpath, $exfile->get_filename())) { if (!$fs->file_exists($context->id, $component, $filearea, $fileareaid, $realpath, $exfile->get_filename())) {
// File or directory did not exist, just move it. // File or directory did not exist, just move it.
$exfile->rename($realpath, $exfile->get_filename()); $exfile->rename($realpath, $exfile->get_filename());
} else if (!$exfile->is_directory()) { } else if (!$exfile->is_directory()) {
// File already existed, overwrite it. // File already existed, overwrite it.
repository::overwrite_existing_draftfile($draftareaid, $realpath, $exfile->get_filename(), $exfile->get_filepath(), if ($file = $fs->get_file($context->id, $component, $filearea, $fileareaid, $realpath, $exfile->get_filename())) {
$exfile->get_filename()); if ($tempfile = $fs->get_file($context->id, $component, $filearea, $fileareaid, $exfile->get_filepath(), $exfile->get_filename())) {
$file->delete();
$fs->create_file_from_storedfile(array('filepath'=>$exfile->get_filepath(), 'filename'=>$exfile->get_filename()), $tempfile);
$tempfile->delete();
}
}
} else { } else {
// Directory already existed, remove temporary dir but make sure we don't remove the existing dir. // Directory already existed, remove temporary dir but make sure we don't remove the existing dir.
$doremovedirs[] = $exfile->get_filepath(); $doremovedirs[] = $exfile->get_filepath();
...@@ -209,7 +216,7 @@ function unzip_task_file_in_draft_area($draftareaid, $usercontext) { ...@@ -209,7 +216,7 @@ function unzip_task_file_in_draft_area($draftareaid, $usercontext) {
} }
// Remove remaining temporary directories. // Remove remaining temporary directories.
foreach (array_diff($doremovedirs, $donotremovedirs) as $filepath) { foreach (array_diff($doremovedirs, $donotremovedirs) as $filepath) {
$file = $fs->get_file($usercontext->id, 'user', 'draft', $draftareaid, $filepath, '.'); $file = $fs->get_file($context->id, $component, $filearea, $fileareaid, $filepath, '.');
if ($file) { if ($file) {
$file->delete(); $file->delete();
} }
...@@ -224,16 +231,18 @@ function unzip_task_file_in_draft_area($draftareaid, $usercontext) { ...@@ -224,16 +231,18 @@ function unzip_task_file_in_draft_area($draftareaid, $usercontext) {
} }
/** /**
* Removes all files and directories from the given draft area except a file with the given file name * Removes all files and directories from the given file area except a file with the given file name
* *
* @param type $draftareaid * @param type $context
* @param type $user_context * @param type $component
* @param type $excluded_file_name * @param type $filearea
* @param type $fileareaid
* @param type $excludedfilename
*/ */
function remove_all_files_from_draft_area($draftareaid, $usercontext, $excludedfilename) function remove_all_files_from_file_area($context, $component, $filearea, $fileareaid, $excludedfilename)
{ {
$fs = get_file_storage(); $fs = get_file_storage();
$files = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftareaid); $files = $fs->get_area_files($context->id, $component, $filearea, $fileareaid);
foreach ($files as $fi) { foreach ($files as $fi) {
if (($fi->is_directory() && $fi->get_filepath() != '/') || ($fi->get_filename() != $excludedfilename && if (($fi->is_directory() && $fi->get_filepath() != '/') || ($fi->get_filename() != $excludedfilename &&
$fi->get_filename() != '.')) { $fi->get_filename() != '.')) {
...@@ -245,26 +254,28 @@ function remove_all_files_from_draft_area($draftareaid, $usercontext, $excludedf ...@@ -245,26 +254,28 @@ function remove_all_files_from_draft_area($draftareaid, $usercontext, $excludedf
/** /**
* Creates a DOMDocument object from the task.xml file in the given file area and returns it. * Creates a DOMDocument object from the task.xml file in the given file area and returns it.
* *
* @param type $user_context * @param type $context
* @param type $draftareaid * @param type $component
* @param type $filearea
* @param type $fileareaid
* @param type $xmlfilename * @param type $xmlfilename
* @param type $zipfilename (optional, only if user uploaded a zip) * @param type $zipfilename (optional, only if user uploaded a zip)
* @return \DOMDocument * @return \DOMDocument
* @throws invalid_parameter_exception * @throws invalid_parameter_exception
*/ */
function create_domdocument_from_task_xml($usercontext, $draftareaid, $xmlfilename, $zipfilename) function create_domdocument_from_task_xml($context, $component, $filearea, $fileareaid, $xmlfilename, $zipfilename)
{ {
$fs = get_file_storage(); $fs = get_file_storage();
$file = $fs->get_file($usercontext->id, 'user', 'draft', $draftareaid, "/", $xmlfilename); $file = $fs->get_file($context->id, $component, $filearea, $fileareaid, "/", $xmlfilename);
if (!$file) { if (!$file) {
remove_all_files_from_draft_area($draftareaid, $usercontext, $zipfilename); remove_all_files_from_file_area($context, $component, $filearea, $fileareaid, $zipfilename);
throw new invalid_parameter_exception('Supplied zip file doesn\'t contain task.xml file.'); throw new invalid_parameter_exception('Supplied zip file doesn\'t contain task.xml file.');
} }
$doc = new DOMDocument(); $doc = new DOMDocument();
if (!$doc->loadXML($file->get_content())) { if (!$doc->loadXML($file->get_content())) {
remove_all_files_from_draft_area($draftareaid, $usercontext, $zipfilename); remove_all_files_from_file_area($context, $component, $filearea, $fileareaid, $zipfilename);
throw new invalid_parameter_exception('Error parsing the supplied ' . $xmlfilename . ' file. See server log for details.'); throw new invalid_parameter_exception('Error parsing the supplied ' . $xmlfilename . ' file. See server log for details.');
} }
...@@ -287,7 +298,7 @@ function get_text_content_from_file($usercontext, $draftareaid, $keepfilename, $ ...@@ -287,7 +298,7 @@ function get_text_content_from_file($usercontext, $draftareaid, $keepfilename, $
$fs = get_file_storage(); $fs = get_file_storage();
$file = $fs->get_file($usercontext->id, 'user', 'draft', $draftareaid, $filepath, $filename); $file = $fs->get_file($usercontext->id, 'user', 'draft', $draftareaid, $filepath, $filename);
if (!$file) { if (!$file) {
remove_all_files_from_draft_area($draftareaid, $usercontext, $keepfilename); remove_all_files_from_file_area($usercontext, 'user', 'draft', $draftareaid, $keepfilename);
throw new invalid_parameter_exception('Supplied file doesn\'t contain file ' . $filepath . $filename . '.'); throw new invalid_parameter_exception('Supplied file doesn\'t contain file ' . $filepath . $filename . '.');
} }
...@@ -316,7 +327,6 @@ function get_text_content_from_file($usercontext, $draftareaid, $keepfilename, $ ...@@ -316,7 +327,6 @@ function get_text_content_from_file($usercontext, $draftareaid, $keepfilename, $
return $content; return $content;
} }
/** /**
* Get the stored_file from the file area PROFORMA_TASKXML_FILEAREA, if any. * Get the stored_file from the file area PROFORMA_TASKXML_FILEAREA, if any.
* @return stored_file|bool the file or false, if not found. * @return stored_file|bool the file or false, if not found.
...@@ -334,18 +344,61 @@ function get_task_xml_file_from_filearea($question) ...@@ -334,18 +344,61 @@ function get_task_xml_file_from_filearea($question)
} }
/**
* @throws stored_file_creation_exception
* @throws dml_exception
* @throws file_exception
* @throws coding_exception
* @throws invalid_parameter_exception
* @throws Exception
*/
function save_task_and_according_files($question) function save_task_and_according_files($question)
{ {
global $USER, $DB; global $USER, $DB;
$fs = get_file_storage();
$context = '';
$component = '';
$filearea = '';
$fileareaid = '';
$filesfordb = array();
if (property_exists($question, 'taskfile') && !is_null($question->taskfile)) {
$context = $question->taskfile['context'];
$component = $question->taskfile['component'];
$filearea = $question->taskfile['filearea'];
$fileareaid = $question->id;
$question->taskfileinfo['itemid'] = $fileareaid;
$fileinfo = [
'contextid' => $context->id,
'component' => $component,
'filearea' => $filearea,
'itemid' => $fileareaid,
'filepath' => $question->taskfile['filepath'],
'filename' => $question->taskfile['filename']
];
$fs->create_file_from_string($fileinfo, $question->taskfile['content']);
if (!isset($question->proformataskfileupload)) { $record = new stdClass();
$record->questionid = $question->id;
$record->fileid = $filearea == PROFORMA_TASKZIP_FILEAREA ? 'task' : 'taskxml';
$record->usedbygrader = 0;
$record->visibletostudents = 'no';
$record->usagebylms = 'download';
$record->filepath = '/';
$record->filename = $fileinfo['filename'];
$record->filearea = $filearea;
$filesfordb[] = $record;
} else if (isset($question->proformataskfileupload)) {
$context = context_user::instance($USER->id);
$component = 'user';
$filearea = 'draft';
$fileareaid = $question->proformataskfileupload;
} else {
return; return;
} }
$draftareaid = $question->proformataskfileupload;
$usercontext = context_user::instance($USER->id);
$unzipinfo = unzip_task_file_in_draft_area($draftareaid, $usercontext); $unzipinfo = unzip_task_file_in_file_area($context, $component, $filearea, $fileareaid);
if (!$unzipinfo) { if (!$unzipinfo) {
// Seems like no task file was submitted. // Seems like no task file was submitted.
return false; return false;
...@@ -355,14 +408,35 @@ function save_task_and_according_files($question) ...@@ -355,14 +408,35 @@ function save_task_and_according_files($question)
$keepfilename = $taskzipfilename != null ? $taskzipfilename : $taskxmlfilename; $keepfilename = $taskzipfilename != null ? $taskzipfilename : $taskxmlfilename;
// Copy all extracted files to the corresponding file area. // Copy all extracted files to the corresponding file area.
file_save_draft_area_files($draftareaid, $question->context->id, COMPONENT_NAME, PROFORMA_ATTACHED_TASK_FILES_FILEAREA, if ($filearea == 'draft') {
file_save_draft_area_files($fileareaid, $question->context->id, COMPONENT_NAME, PROFORMA_ATTACHED_TASK_FILES_FILEAREA,
$question->id, array('subdirs' => true)); $question->id, array('subdirs' => true));
} else {
foreach ($fs->get_area_files($context->id, $component, $filearea, $fileareaid) AS $file) {
if ($file->get_filename() != '.' && $file->get_filename() != $taskzipfilename /* Skip taskfile because its already present in the correct filearea*/) {
$newfileinfo = array(
'contextid' => $context->id,
'component' => COMPONENT_NAME,
'filearea' => PROFORMA_ATTACHED_TASK_FILES_FILEAREA,
'itemid' => $question->id,
'filepath' => $file->get_filepath(),
'filename' => $file->get_filename()
);
$doc = create_domdocument_from_task_xml($usercontext, $draftareaid, $taskxmlfilename, $taskzipfilename); // Check if the file exists.
if (!$fs->file_exists($newfileinfo['contextid'], $newfileinfo['component'], $newfileinfo['filearea'], $newfileinfo['itemid'], $newfileinfo['filepath'], $newfileinfo['filename'])) {
$createdFile = $fs->create_file_from_storedfile($newfileinfo, $file);
if (!$createdFile) {
throw new Exception('Could not create task from moodle xml.');
}
}
}
}
}
$doc = create_domdocument_from_task_xml($context, $component, $filearea, $fileareaid, $taskxmlfilename, $taskzipfilename);
$namespace = detect_proforma_namespace($doc); $namespace = detect_proforma_namespace($doc);
$filesfordb = array();
$fs = get_file_storage();
$embeddedelems = array("embedded-bin-file", "embedded-txt-file"); $embeddedelems = array("embedded-bin-file", "embedded-txt-file");
$attachedelems = array("attached-bin-file", "attached-txt-file"); $attachedelems = array("attached-bin-file", "attached-txt-file");
foreach ($doc->getElementsByTagNameNS($namespace, 'file') as $file) { foreach ($doc->getElementsByTagNameNS($namespace, 'file') as $file) {
...@@ -428,6 +502,7 @@ function save_task_and_according_files($question) ...@@ -428,6 +502,7 @@ function save_task_and_according_files($question)
} }
// Now move the task xml file to the designated area. // Now move the task xml file to the designated area.
if ($filearea == 'draft' || ($taskzipfilename != null /* Taskxmlfile already present in the correct filearea */)) {
$file = $fs->get_file($question->context->id, COMPONENT_NAME, PROFORMA_ATTACHED_TASK_FILES_FILEAREA, $question->id, $file = $fs->get_file($question->context->id, COMPONENT_NAME, PROFORMA_ATTACHED_TASK_FILES_FILEAREA, $question->id,
'/', $taskxmlfilename); '/', $taskxmlfilename);
$newfilerecord = array( $newfilerecord = array(
...@@ -450,8 +525,9 @@ function save_task_and_according_files($question) ...@@ -450,8 +525,9 @@ function save_task_and_according_files($question)
$record->filename = $taskxmlfilename; $record->filename = $taskxmlfilename;
$record->filearea = PROFORMA_TASKXML_FILEAREA; $record->filearea = PROFORMA_TASKXML_FILEAREA;
$filesfordb[] = $record; $filesfordb[] = $record;
}
if ($taskzipfilename != null) { if ($taskzipfilename != null && $filearea == 'draft' /* Taskzipfile already present in the correct filearea */) {
// Now move the task zip file to the designated area. // Now move the task zip file to the designated area.
$file = $fs->get_file($question->context->id, COMPONENT_NAME, PROFORMA_ATTACHED_TASK_FILES_FILEAREA, $question->id, '/', $taskzipfilename); $file = $fs->get_file($question->context->id, COMPONENT_NAME, PROFORMA_ATTACHED_TASK_FILES_FILEAREA, $question->id, '/', $taskzipfilename);
$newfilerecord = array( $newfilerecord = array(
...@@ -480,7 +556,7 @@ function save_task_and_according_files($question) ...@@ -480,7 +556,7 @@ function save_task_and_according_files($question)
$DB->insert_records('qtype_moopt_files', $filesfordb); $DB->insert_records('qtype_moopt_files', $filesfordb);
// Do a little bit of cleanup and remove everything from the file area we extracted. // Do a little bit of cleanup and remove everything from the file area we extracted.
remove_all_files_from_draft_area($draftareaid, $usercontext, $keepfilename); remove_all_files_from_file_area($context, $component, $filearea, $fileareaid, $keepfilename);
} }
/** /**
......
...@@ -69,15 +69,19 @@ class qtype_moopt extends question_type { ...@@ -69,15 +69,19 @@ class qtype_moopt extends question_type {
*/ */
public function save_question_options($question) { public function save_question_options($question) {
// Convert the combined representation of the graderID to graderName and graderVersion // Convert the combined representation of the graderID to graderName and graderVersion
if (property_exists($question, 'graderselect') && !is_null($question->graderselect)) {
$separatedGraderID = get_name_and_version_from_graderid_html_representation($question->graderselect); $separatedGraderID = get_name_and_version_from_graderid_html_representation($question->graderselect);
$question->gradername = $separatedGraderID->gradername; $question->gradername = $separatedGraderID->gradername;
$question->graderversion = $separatedGraderID->graderversion; $question->graderversion = $separatedGraderID->graderversion;
}
if (!isset($question->internaldescription['text'])) { if (is_array($question->internaldescription)) {
if (!array_key_exists('text', $question->internaldescription) || !isset($question->internaldescription['text'])) {
$question->internaldescription = ''; $question->internaldescription = '';
} else { } else {
$question->internaldescription = trim($question->internaldescription['text']); $question->internaldescription = trim($question->internaldescription['text']);
} }
}
parent::save_question_options($question); parent::save_question_options($question);
...@@ -95,7 +99,9 @@ class qtype_moopt extends question_type { ...@@ -95,7 +99,9 @@ class qtype_moopt extends question_type {
// Store custom settings for free text input fields. // Store custom settings for free text input fields.
$DB->delete_records('qtype_moopt_freetexts', array('questionid' => $question->id)); $DB->delete_records('qtype_moopt_freetexts', array('questionid' => $question->id));
if ($question->{'enablefreetextsubmissions'} && $question->{'enablecustomsettingsforfreetextinputfields'}) {
if (property_exists($question, 'enablefreetextsubmissions') && $question->{'enablefreetextsubmissions'} &&
property_exists($question, 'enablecustomsettingsforfreetextinputfields') && $question->{'enablecustomsettingsforfreetextinputfields'}) {
$maxfts = $question->ftsmaxnumfields; $maxfts = $question->ftsmaxnumfields;
// make sure this user-entered max num does not exceed the // make sure this user-entered max num does not exceed the
// original plugin setting from when it was installed and first-time configured // original plugin setting from when it was installed and first-time configured
...@@ -104,7 +110,7 @@ class qtype_moopt extends question_type { ...@@ -104,7 +110,7 @@ class qtype_moopt extends question_type {
throw new \coding_exception("Assertion error: user-entered max free text input fields cannot be greater than the plugin's max number setting."); throw new \coding_exception("Assertion error: user-entered max free text input fields cannot be greater than the plugin's max number setting.");
for ($i = 0; $i < $maxfts; $i++) { for ($i = 0; $i < $maxfts; $i++) {
if ($question->{"enablecustomsettingsforfreetextinputfield$i"}) { if (property_exists($question, "enablecustomsettingsforfreetextinputfield$i") && $question->{"enablecustomsettingsforfreetextinputfield$i"}) {
$data = new stdClass(); $data = new stdClass();
$data->questionid = $question->id; $data->questionid = $question->id;
$data->inputindex = $i; $data->inputindex = $i;
...@@ -135,4 +141,135 @@ class qtype_moopt extends question_type { ...@@ -135,4 +141,135 @@ class qtype_moopt extends question_type {
parent::delete_question($questionid, $contextid); parent::delete_question($questionid, $contextid);
} }
/**
* Provide export functionality for xml format
* @param question object the question object
* @param format object the format object so that helper methods can be used
* @param extra mixed any additional format specific data that may be passed by the format (see format code for info)
* @return string the data to append to the output buffer or false if error
*/
function export_to_xml($question, $format, $extra=null) {
global $DB, $COURSE;
$xml = new XMLWriter();
$xml->openMemory();
$xml->setIndent(1);
$xml->setIndentString(' ');
/* Add an empty answer-Element because Moodle-Import function expects it */
$xml->startElement('answer');
$xml->writeAttribute('fraction', 0);
$xml->writeElement('text', '');
$xml->endElement();
$fs = get_file_storage();
$taskFileRecord = $DB->get_record('qtype_moopt_files', array('questionid' => $question->id, 'fileid' => 'task'));
if (!$taskFileRecord) {
// taskxml file without zip
$taskFileRecord = $DB->get_record('qtype_moopt_files', array('questionid' => $question->id, 'fileid' => 'taskxml'));
}
$context = context_course::instance($COURSE->id);
$taskfile = $fs->get_file($context->id,COMPONENT_NAME, $taskFileRecord->filearea, $question->id, $taskFileRecord->filepath, $taskFileRecord->filename);
$taskfilename = $taskfile->get_filename();
$taskfilepath = $taskfile->get_filepath();
$taskfileencoding = 'base64';
$taskfilecontentbase64 = base64_encode($taskfile->get_content());
$xml->startElement('taskfile');
$xml->writeAttribute('filearea', $taskFileRecord->filearea);
$xml->writeAttribute('name', $taskfilename);
$xml->writeAttribute('path', $taskfilepath);
$xml->writeAttribute('encoding', $taskfileencoding);
$xml->writeRaw($taskfilecontentbase64);
$xml->endElement();
/* Add freetext specific options to export */
$customOptionsForAllFreetexts = $DB->get_records('qtype_moopt_freetexts', array('questionid' => $question->id));
if (count($customOptionsForAllFreetexts) > 0) {
$xml->startElement('customsettingsforfreetextinputfields');
foreach ($customOptionsForAllFreetexts as $customOptionsForOneFreetext) {
$inputindex = $customOptionsForOneFreetext->inputindex;
$xml->startElement('field');
$xml->writeAttribute('index', $inputindex);
$presetfilename = $customOptionsForOneFreetext->presetfilename ? "0" : "1"; //Invert because in the form later "0" means true
$xml->writeElement('namesettingsforfreetextinput', $presetfilename);
$xml->writeElement('freetextinputfieldname', $customOptionsForOneFreetext->filename);
$xml->writeElement('ftsoverwrittenlang', $customOptionsForOneFreetext->ftslang);
$xml->writeElement('ftsinitialdisplayrows', $customOptionsForOneFreetext->initialdisplayrows);
$xml->startElement('freetextinputfieldtemplate');
$xml->writeCdata($customOptionsForOneFreetext->filecontent);
$xml->endElement();
$xml->endElement();
}
$xml->endElement();
}
$xmloutput = $xml->outputMemory();
$xmloutput .= parent::export_to_xml($question, $format, $extra);
return $xmloutput;
}
/**
* Provide import functionality for xml format
* @param data mixed the segment of data containing the question
* @param question object question object processed (so far) by standard import code
* @param format object the format object so that helper methods can be used (in particular error() )
* @param extra mixed any additional format specific data that may be passed by the format (see format code for info)
* @return object question object suitable for save_options() call or false if cannot handle
*/
function import_from_xml($data, $question, $format, $extra=null) {
global $COURSE;
$ret = parent::import_from_xml($data, $question, $format, $extra);
$root = $data['#'];
/* Import Taskfile */
if ($ret && array_key_exists('taskfile', $root)) {
$taskfileattributes = $root['taskfile'][0]['@'];
$taskfilearea = $taskfileattributes['filearea'];
$taskfilename = $taskfileattributes['name'];
$taskfilepath = $taskfileattributes['path'];
$taskfileencoding = $taskfileattributes['encoding'];
$taskfileencoded = $root['taskfile'][0]['#'];
/* Check encoding of */
$taskfilecontent = false;
if (strtolower($taskfileencoding) == 'base64') {
$taskfilecontent = base64_decode($taskfileencoded, true);
}
if (!$taskfilecontent) {
throw new InvalidArgumentException("The taskfile could not be encoded from moodle xml.");
}
$context = context_course::instance($COURSE->id);
$taskfileinfo = [
'context' => $context,
'component' => COMPONENT_NAME,
'filearea' => $taskfilearea,
'filepath' => $taskfilepath,
'filename' => $taskfilename,
'content' => $taskfilecontent
]; // Only save the taskfile information here and save the file later because question id is unknown until later
$ret->taskfile = $taskfileinfo;
}
/* Import custom settings for FreetextInputFields */
if ($ret && array_key_exists('customsettingsforfreetextinputfields', $root)) {
$ret->{'enablecustomsettingsforfreetextinputfields'} = true;
$customsettingsforfreetextinputfields = $root['customsettingsforfreetextinputfields'][0]['#']['field'];
foreach ($customsettingsforfreetextinputfields AS $field) {
$inputIndex = $field['@']['index'];
$ret->{'enablecustomsettingsforfreetextinputfield' . $inputIndex} = true;
$options = $field['#'];
foreach ($options AS $option => $optionValue) {
$ret->{$option . $inputIndex} = $optionValue[0]['#'];
}
}
}
return $ret;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment