From 49220fa70cc90013773771727f0f36103a19f88b Mon Sep 17 00:00:00 2001 From: moodler <moodler> Date: Sun, 16 Feb 2003 07:08:57 +0000 Subject: [PATCH] Various quiz changes. Most importantly is the new framework for importing quiz questions. Importing works but is still being tested. --- lang/en/help/quiz/import.html | 49 +++++++++ lang/en/quiz.php | 6 ++ lang/en/survey.php | 7 ++ mod/quiz/db/mysql.php | 6 +- mod/quiz/db/postgres7.php | 6 +- mod/quiz/format/README | 6 ++ mod/quiz/format/custom.php | 63 ++++++++++++ mod/quiz/format/default.php | 81 +++++++++++++++ mod/quiz/format/missingword.php | 90 +++++++++++++++++ mod/quiz/format/qti.php | 42 ++++++++ mod/quiz/format/webct.php | 42 ++++++++ mod/quiz/import.php | 107 ++++++++++++++++++++ mod/quiz/lib.php | 174 +++++++++++++++++++++++++++++++- mod/quiz/question.php | 166 ++++-------------------------- mod/quiz/version.php | 2 +- 15 files changed, 695 insertions(+), 152 deletions(-) create mode 100644 lang/en/help/quiz/import.html create mode 100644 mod/quiz/format/README create mode 100644 mod/quiz/format/custom.php create mode 100644 mod/quiz/format/default.php create mode 100644 mod/quiz/format/missingword.php create mode 100644 mod/quiz/format/qti.php create mode 100644 mod/quiz/format/webct.php create mode 100644 mod/quiz/import.php diff --git a/lang/en/help/quiz/import.html b/lang/en/help/quiz/import.html new file mode 100644 index 0000000000..0ce15388ec --- /dev/null +++ b/lang/en/help/quiz/import.html @@ -0,0 +1,49 @@ +<P ALIGN=CENTER><B>Importing new questions</B></P> + +<P>This function allows you to import questions from + external text files. + +<P>Several common file formats are supported: + +<P><B>Missing word format</B></P> +<UL> +<P>This format only supports multiple choice questions. +Each answer is separated with a tilde (~), and the correct answer is +prefixed with an equals sign (=). Here is an example: + +<BLOCKQUOTE>As soon as we begin to explore our body parts as infants +we become students of {=anatomy and physiology ~reflexology +~science ~experiment}, and in a sense we remain students for life. +</BLOCKQUOTE> + +<P>More info: <? helpbutton("formatmissingword", "", "quiz") ?></P> +</UL> + + +<P><B>IMS QTI format</B></P> +<UL> +<P>The standard format for Question and Test Interoperability, from IMS. +<P>Not yet implemented + +<P>More info: <? helpbutton("formatqti", "", "quiz") ?></P> +</UL> + + +<P><B>WebCT format</B></P> +<UL> +<P>The format of files exported from WebCT. +<P>Not yet implemented + +<P>More info: <? helpbutton("formatwebct", "", "quiz") ?></P> +</UL> + +<P><B>Custom format</B></P> +<UL> +<P>If you have your own format that you need to import, you can + implement it yourself by editing mod/quiz/format/custom.php + +<P>The amount of new code needed is quite small - just enough + to parse a single question from given text. + +<P>More info: <? helpbutton("formatcustom", "", "quiz") ?></P> +</UL> diff --git a/lang/en/quiz.php b/lang/en/quiz.php index 9af28c6c19..4ca8a6c38a 100644 --- a/lang/en/quiz.php +++ b/lang/en/quiz.php @@ -5,6 +5,7 @@ $string['modulename'] = "Quiz"; $string['modulenameplural'] = "Quizzes"; #------------------------------------------------------------ +$string['addquestions'] = "Add questions"; $string['addselectedtoquiz'] = "Add selected to quiz"; $string['allowreview'] = "Allow review"; $string['alwaysavailable'] = "Always available"; @@ -35,6 +36,7 @@ $string['choices'] = "Available choices"; $string['correctanswer'] = "Correct answer"; $string['correctanswers'] = "Correct answers"; $string['createnewquestion'] = "Create new question"; +$string['custom'] = "Custom format"; $string['daysavailable'] = "Days available"; $string['default'] = "Default"; $string['defaultinfo'] = "The default category for questions."; @@ -60,10 +62,12 @@ $string['gradehighest'] = "Highest grade"; $string['grademethod'] = "Grading method"; $string['guestsno'] = "Sorry, guests can not see or attempt quizzes"; $string['imagedisplay'] = "Image to display"; +$string['importquestions'] = "Import questions from file"; $string['introduction'] = "Introduction"; $string['marks'] = "Marks"; $string['missingname'] = "Missing question name"; $string['missingquestiontext'] = "Missing question text"; +$string['missingword'] = "Missing word format"; $string['multichoice'] = "Multiple Choice"; $string['noanswers'] = "No answers were selected!"; $string['noattempts'] = "No attempts have been made on this quiz"; @@ -72,6 +76,7 @@ $string['noquestions'] = "No questions have been added yet"; $string['noreview'] = "You are not allowed to review this quiz"; $string['noreviewuntil'] = "You are not allowed to review this quiz until \$a"; $string['publish'] = "Publish"; +$string['qti'] = "IMS QTI format"; $string['question'] = "Question"; $string['questioninuse'] = "The question '\$a' is currently being used:"; $string['questions'] = "Questions"; @@ -106,4 +111,5 @@ $string['true'] = "True"; $string['truefalse'] = "True/False"; $string['type'] = "Type"; $string['viewallanswers'] = "View \$a completed quizzes"; +$string['webct'] = "WebCT format"; $string['yourfinalgradeis'] = "Your final grade for this quiz is \$a"; diff --git a/lang/en/survey.php b/lang/en/survey.php index 8081e1102c..03416bc39c 100644 --- a/lang/en/survey.php +++ b/lang/en/survey.php @@ -63,6 +63,13 @@ $string['attlsmintro'] = "In discussion ..."; $string['attlsm1'] = "Attitudes Towards Thinking and Learning"; $string['attlsm2'] = "Connected Learning"; $string['attlsm3'] = "Separate Learning"; +$string['ciqname'] = "Critical Incidents"; +$string['ciqintro'] = "While thinking about the events in this class over the past week, answer the questions below."; +$string['ciq1'] = "At what moment in class were you most engaged as a learner?"; +$string['ciq2'] = "At what moment in class were you most distanced as a learner?"; +$string['ciq3'] = "What action from anyone in the forums did you find most affirming or helpful?"; +$string['ciq4'] = "What action from anyone in the forums did you find most puzzling or confusing?"; +$string['ciq5'] = "What event surprised you most?"; $string['clicktocontinue'] = "Click here to continue"; $string['clicktocontinuecheck'] = "Click here to check and continue"; diff --git a/mod/quiz/db/mysql.php b/mod/quiz/db/mysql.php index 11c787380a..ccc5c76651 100644 --- a/mod/quiz/db/mysql.php +++ b/mod/quiz/db/mysql.php @@ -36,9 +36,9 @@ function quiz_upgrade($oldversion) { } if ($oldversion < 2003010301) { - table_column("quiz_truefalse", "true", "trueanswer", "INTEGER", "UNSIGNED", "0", "NOT NULL", ""); - table_column("quiz_truefalse", "false", "falseanswer", "INTEGER", "UNSIGNED", "0", "NOT NULL", ""); - table_column("quiz_questions", "type", "qtype", "INTEGER", "UNSIGNED", "0", "NOT NULL", ""); + table_column("quiz_truefalse", "true", "trueanswer", "INTEGER", "10", "UNSIGNED", "0", "NOT NULL", ""); + table_column("quiz_truefalse", "false", "falseanswer", "INTEGER", "10", "UNSIGNED", "0", "NOT NULL", ""); + table_column("quiz_questions", "type", "qtype", "INTEGER", "10", "UNSIGNED", "0", "NOT NULL", ""); } return true; diff --git a/mod/quiz/db/postgres7.php b/mod/quiz/db/postgres7.php index bc7010d2c6..c839413c88 100644 --- a/mod/quiz/db/postgres7.php +++ b/mod/quiz/db/postgres7.php @@ -11,9 +11,9 @@ function quiz_upgrade($oldversion) { } if ($oldversion < 2003010301) { - table_column("quiz_truefalse", "true", "trueanswer", "INTEGER", "UNSIGNED", "0", "NOT NULL", ""); - table_column("quiz_truefalse", "false", "falseanswer", "INTEGER", "UNSIGNED", "0", "NOT NULL", ""); - table_column("quiz_questions", "type", "qtype", "INTEGER", "UNSIGNED", "0", "NOT NULL", ""); + table_column("quiz_truefalse", "true", "trueanswer", "INTEGER", "10", "UNSIGNED", "0", "NOT NULL", ""); + table_column("quiz_truefalse", "false", "falseanswer", "INTEGER", "10", "UNSIGNED", "0", "NOT NULL", ""); + table_column("quiz_questions", "type", "qtype", "INTEGER", "10", "UNSIGNED", "0", "NOT NULL", ""); } return true; diff --git a/mod/quiz/format/README b/mod/quiz/format/README new file mode 100644 index 0000000000..a850f67dd4 --- /dev/null +++ b/mod/quiz/format/README @@ -0,0 +1,6 @@ +This directory contains plug-in sub-modules to add +import-export formats to Moodle quizzes. + +Each sub-module is a file containing a class that +contains functions for reading, writing, importing +and exporting quiz questions. diff --git a/mod/quiz/format/custom.php b/mod/quiz/format/custom.php new file mode 100644 index 0000000000..dacb12784f --- /dev/null +++ b/mod/quiz/format/custom.php @@ -0,0 +1,63 @@ +<?PHP // $Id$ + +//////////////////////////////////////////////////////////////////////////// +/// CUSTOM FORMAT +/// +/// This format provides a starting point for creating your own +/// import format. +/// +/// If your questions are separated by blank lines, then you will +/// only need to modify the readquestion() function to parse the +/// lines into each question. See default.php for the other +/// functions that you may need to override if you have different +/// needs. +/// +/// See missingword.php for an example of how it's done, and see +/// the top of ../lib.php for some constants you might need. +/// +//////////////////////////////////////////////////////////////////////////// + +require("default.php"); + +class quiz_file_format extends quiz_default_format { + + function readquestions($lines) { + /// Parses an array of lines into an array of questions, + /// where each item is a question object as defined by + /// readquestion(). Questions are defined as anything + /// between blank lines. + + $questions = array(); + $currentquestion = array(); + + foreach ($lines as $line) { + $line = trim($line); + if (empty($line)) { + if (!empty($currentquestion)) { + if ($question = $this->readquestion($currentquestion)) { + $questions[] = $question; + } + $currentquestion = array(); + } + } else { + $currentquestion[] = $line; + } + } + + return $questions; + } + + + + function readquestion($lines) { + /// Given an array of lines known to define a question in + /// this format, this function converts it into a question + /// object suitable for processing and insertion into Moodle. + + $question = NULL; + + return $question; + } +} + +?> diff --git a/mod/quiz/format/default.php b/mod/quiz/format/default.php new file mode 100644 index 0000000000..0f7b70c91e --- /dev/null +++ b/mod/quiz/format/default.php @@ -0,0 +1,81 @@ +<?PHP // $Id$ + +//////////////////////////////////////////////////////////////////// +/// Default class for file imports/exports. // +/// // +/// Doesn't do everything on it's own -- it needs to be extended. // +//////////////////////////////////////////////////////////////////// + + +class quiz_default_format { + + var $displayerrors = true; + +/// Importing functions + + function readdata($filename) { + /// Returns complete file with an array, one item per line + + if (is_readable($filename)) { + return file($filename); + } + return false; + } + + + function readquestions($lines) { + /// Parses an array of lines into an array of questions, + /// where each item is a question object as defined by + /// readquestion(). Questions are defines as anything + /// between blank lines. + + $questions = array(); + $currentquestion = array(); + + foreach ($lines as $line) { + $line = trim($line); + if (empty($line)) { + if (!empty($currentquestion)) { + if ($question = $this->readquestion($currentquestion)) { + $questions[] = $question; + } + $currentquestion = array(); + } + } else { + $currentquestion[] = $line; + } + } + + return $questions; + } + + + function readquestion($lines) { + /// Given an array of lines known to define a question in + /// this format, this function converts it into a question + /// object suitable for processing and insertion into Moodle. + + echo "<p>You need to override the readquestion() function"; + + return NULL; + } + + + function swapshuffle($array) { + /// Given a simple array, shuffles it up just like shuffle() + /// Unlike PHP's shuffle() ihis function works on any machine. + + srand ((double) microtime() * 10000000); + $last = count($array) - 1; + for ($i=0;$i<=$last;$i++) { + $from = rand(0,$last); + $curr = $array[$i]; + $array[$i] = $array[$from]; + $array[$from] = $curr; + } + return $array; + } + +} + +?> diff --git a/mod/quiz/format/missingword.php b/mod/quiz/format/missingword.php new file mode 100644 index 0000000000..8add2708c5 --- /dev/null +++ b/mod/quiz/format/missingword.php @@ -0,0 +1,90 @@ +<?PHP // $Id$ + +//////////////////////////////////////////////////////////////////////////// +/// MISSING WORD FORMAT +/// +/// This Moodle class provides all functions necessary to import and export +/// one-correct-answer multiple choice questions in this format: +/// +/// As soon as we begin to explore our body parts as infants +/// we become students of {=anatomy and physiology ~reflexology +/// ~science ~experiment}, and in a sense we remain students for life. +/// +/// Each answer is separated with a tilde ~, and the correct answer is +/// prefixed with an equals sign = +/// +//////////////////////////////////////////////////////////////////////////// + +require("default.php"); + +class quiz_file_format extends quiz_default_format { + + function readquestion($lines) { + /// Given an array of lines known to define a question in + /// this format, this function converts it into a question + /// object suitable for processing and insertion into Moodle. + + $question = NULL; + + $text = implode($lines, " "); + + /// Find answer section + + $answerstart = strpos($text, "{"); + if ($answerstart === false) { + if ($this->displayerrors) { + echo "<P>$text<P>Could not find a {"; + } + return false; + } + + $answerfinish = strpos($text, "}"); + if ($answerfinish === false) { + if ($this->displayerrors) { + echo "<P>$text<P>Could not find a }"; + } + return false; + } + + $answerlength = $answerfinish - $answerstart; + $answertext = substr($text, $answerstart + 1, $answerlength - 1); + + /// Save the new question text + $question->questiontext = addslashes(substr_replace($text, "_____", $answerstart, $answerlength+1)); + $question->name = $question->questiontext; + + + /// Parse the answers + $answers = explode("~", $answertext); + + if (! count($answers)) { + if ($this->displayerrors) { + echo "<P>No answers found in $answertext"; + } + return false; + } + + $answers = $this->swapshuffle($answers); + + foreach ($answers as $key => $answer) { + $answer = trim($answer); + if ($answer[0] == "=") { + $question->fraction[$key] = 1; + $answer = substr($answer, 1); + } else { + $question->fraction[$key] = 0; + } + $question->answer[$key] = addslashes($answer); + $question->feedback[$key] = ""; + } + + $question->qtype = MULTICHOICE; + $question->single = 1; // Only one answer is allowed + $question->image = ""; // No images with this format + + return $question; + } + +} + +?> diff --git a/mod/quiz/format/qti.php b/mod/quiz/format/qti.php new file mode 100644 index 0000000000..ca996eef52 --- /dev/null +++ b/mod/quiz/format/qti.php @@ -0,0 +1,42 @@ +<?PHP // $Id$ + +//////////////////////////////////////////////////////////////////////////// +/// IMS QTI FORMAT +/// +/// This Moodle class provides all functions necessary to import and export +/// QTI-formatted XML question files. +/// +//////////////////////////////////////////////////////////////////////////// + +require("default.php"); + +class quiz_file_format extends quiz_default_format { + + function readquestions($lines) { + /// Parses an array of lines into an array of questions, + /// where each item is a question object as defined by + /// readquestion(). + + $questions = array(); + + /// FIXME + + return $questions; + } + + + function readquestion($lines) { + /// Given an array of lines known to define a question in + /// this format, this function converts it into a question + /// object suitable for processing and insertion into Moodle. + + $question = NULL; + + /// FIXME + + return $question; + } + +} + +?> diff --git a/mod/quiz/format/webct.php b/mod/quiz/format/webct.php new file mode 100644 index 0000000000..3d7bfea60d --- /dev/null +++ b/mod/quiz/format/webct.php @@ -0,0 +1,42 @@ +<?PHP // $Id$ + +//////////////////////////////////////////////////////////////////////////// +/// WEBCT FORMAT +/// +/// This Moodle class provides all functions necessary to import and export +/// WebCT-formatted question files. +/// +//////////////////////////////////////////////////////////////////////////// + +require("default.php"); + +class quiz_file_format extends quiz_default_format { + + function readquestions($lines) { + /// Parses an array of lines into an array of questions, + /// where each item is a question object as defined by + /// readquestion(). + + $questions = array(); + + /// FIXME + + return $questions; + } + + + function readquestion($lines) { + /// Given an array of lines known to define a question in + /// this format, this function converts it into a question + /// object suitable for processing and insertion into Moodle. + + $question = NULL; + + /// FIXME + + return $question; + } + +} + +?> diff --git a/mod/quiz/import.php b/mod/quiz/import.php new file mode 100644 index 0000000000..8ca8c1d43c --- /dev/null +++ b/mod/quiz/import.php @@ -0,0 +1,107 @@ +<?PHP // $Id$ + // Import quiz questions into the given category + + require_once("../../config.php"); + require_once("lib.php"); + + require_variable($category); + optional_variable($format); + + if (! $category = get_record("quiz_categories", "id", $category)) { + error("This wasn't a valid category!"); + } + + if (! $course = get_record("course", "id", $category->course)) { + error("This category doesn't belong to a valid course!"); + } + + require_login($course->id); + + if (!isteacher($course->id)) { + error("Only the teacher can import quiz questions!"); + } + + $streditingquiz = get_string("editingquiz", "quiz"); + $strimportquestions = get_string("importquestions", "quiz"); + + print_header("$course->shortname: $strimportquestions", "$course->shortname: $strimportquestions", + "<A HREF=\"$CFG->wwwroot/course/view.php?id=$course->id\">$course->shortname</A> + -> <A HREF=\"edit.php\">$streditingquiz</A> -> $strimportquestions"); + + if ($form = data_submitted()) { /// Filename + + if (!empty($_FILES['newfile'])) { + $newfile = $_FILES['newfile']; + } + if (empty($newfile)) { + notify(get_string("uploadnofilefound") ); + } else if (!is_uploaded_file($newfile['tmp_name']) or $newfile['size'] == 0) { + notify(get_string("uploadproblem") ); + } else { + + if (! is_readable("format/$form->format".".php")) { + error("Format not known ($form->format)"); + } + + require("format/$form->format".".php"); + + $format = new quiz_file_format(); + + if (! $lines = $format->readdata($newfile['tmp_name'])) { + error("File could not be read, or was empty"); + } + + if (! $questions = $format->readquestions($lines)) { + error("There are no questions in this file!"); + } + + notify("Importing ".count($questions)." questions"); + + $count = 0; + foreach ($questions as $question) { + $count++; + echo "<HR>"; + echo "<P>$count<BR>".stripslashes($question->questiontext)."</P>"; + + $question->category = $category->id; + + if (!$question->id = insert_record("quiz_questions", $question)) { + error("Could not insert new question!"); + } + + // Now to save all the answers and type-specific options + + $result = quiz_save_question_options($question); + + if (!empty($result->error)) { + error($result->error); + } + + if (!empty($result->notice)) { + notice($result->notice); + } + + } + print_continue("edit.php"); + print_footer($course); + exit; + } + } + + /// Print upload form + + echo "<DIV ALIGN=CENTER>"; + echo "<FORM ENCTYPE=\"multipart/form-data\" METHOD=\"POST\" ACTION=import.php>"; + choose_from_menu($QUIZ_FILE_FORMAT, "format", "missingword", ""); + helpbutton("import", $strimportquestions, "quiz"); + echo "<BR>"; + echo " <INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">"; + echo " <INPUT NAME=\"newfile\" TYPE=\"file\" size=\"50\">"; + echo " <INPUT TYPE=submit NAME=save VALUE=\"".get_string("uploadthisfile")."\">"; + echo "</FORM>"; + echo "</DIV>"; + + print_footer($course); + + +?> diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php index f2ea641bb8..481d9e487b 100644 --- a/mod/quiz/lib.php +++ b/mod/quiz/lib.php @@ -21,6 +21,11 @@ $QUIZ_QUESTION_TYPE = array ( MULTICHOICE => get_string("multichoice", "quiz"), TRUEFALSE => get_string("truefalse", "quiz"), SHORTANSWER => get_string("shortanswer", "quiz") ); +$QUIZ_FILE_FORMAT = array ( "custom" => get_string("custom", "quiz"), + "webct" => get_string("webct", "quiz"), + "qti" => get_string("qti", "quiz"), + "missingword" => get_string("missingword", "quiz") ); + define("QUIZ_PICTURE_DEFAULT_HEIGHT", "200"); /// FUNCTIONS /////////////////////////////////////////////////////////////////// @@ -738,6 +743,8 @@ function quiz_print_cat_question_list($categoryid) { $strcategory = get_string("category", "quiz"); $strquestion = get_string("question", "quiz"); + $straddquestions = get_string("addquestions", "quiz"); + $strimportquestions = get_string("importquestions", "quiz"); $strnoquestions = get_string("noquestions", "quiz"); $strselect = get_string("select", "quiz"); $strcreatenewquestion = get_string("createnewquestion", "quiz"); @@ -761,13 +768,24 @@ function quiz_print_cat_question_list($categoryid) { echo "<CENTER>"; echo text_to_html($category->info); + echo "<TABLE><TR>"; + echo "<TD valign=top><B>$straddquestions:</B></TD>"; + echo "<TD valign=top align=right>"; echo "<FORM METHOD=GET ACTION=question.php>"; - echo "<B>$strquestion:</B> "; choose_from_menu($QUIZ_QUESTION_TYPE, "qtype", "", ""); echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">"; echo "<INPUT TYPE=submit VALUE=\"$strcreatenewquestion\">"; helpbutton("questiontypes", $strcreatenewquestion, "quiz"); echo "</FORM>"; + + echo "<FORM METHOD=GET ACTION=import.php>"; + echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">"; + echo "<INPUT TYPE=submit VALUE=\"$strimportquestions\">"; + helpbutton("import", $strimportquestions, "quiz"); + echo "</FORM>"; + + echo "</TR></TABLE>"; + echo "</CENTER>"; if (!$questions = get_records("quiz_questions", "category", $category->id)) { @@ -1106,5 +1124,159 @@ function quiz_grade_attempt_results($quiz, $questions) { } +function quiz_save_question_options($question) { +/// Given some question info and some data about the the answers +/// this function parses, organises and saves the question +/// It is used by question.php when saving new data from a +/// form, and also by import.php when importing questions +/// +/// Returns $result->error or $result->notice + switch ($question->qtype) { + case SHORTANSWER: + // Delete all the old answers + // FIXME - instead of deleting, update existing answers + // so as not to break existing references to them + delete_records("quiz_answers", "question", $question->id); + delete_records("quiz_shortanswer", "question", $question->id); + + $answers = array(); + $maxfraction = -1; + + // Insert all the new answers + foreach ($question->answer as $key => $dataanswer) { + if ($dataanswer != "") { + unset($answer); + $answer->answer = $dataanswer; + $answer->question = $question->id; + $answer->fraction = $question->fraction[$key]; + $answer->feedback = $question->feedback[$key]; + if (!$answer->id = insert_record("quiz_answers", $answer)) { + $result->error = "Could not insert quiz answer!"; + return $result; + } + $answers[] = $answer->id; + if ($question->fraction[$key] > $maxfraction) { + $maxfraction = $question->fraction[$key]; + } + } + } + + unset($options); + $options->question = $question->id; + $options->answers = implode(",",$answers); + $options->usecase = $question->usecase; + if (!insert_record("quiz_shortanswer", $options)) { + $result->error = "Could not insert quiz shortanswer options!"; + return $result; + } + + /// Perform sanity checks on fractional grades + if ($maxfraction != 1) { + $maxfraction = $maxfraction * 100; + $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); + return $result; + } + break; + case TRUEFALSE: + // FIXME - instead of deleting, update existing answers + // so as not to break existing references to them + delete_records("quiz_answers", "question", $question->id); + delete_records("quiz_truefalse", "question", $question->id); + + $true->answer = get_string("true", "quiz"); + $true->question = $question->id; + $true->fraction = $question->answer; + $true->feedback = $question->feedbacktrue; + if (!$true->id = insert_record("quiz_answers", $true)) { + $result->error = "Could not insert quiz answer \"true\")!"; + return $result; + } + + $false->answer = get_string("false", "quiz"); + $false->question = $question->id; + $false->fraction = 1 - (int)$question->answer; + $false->feedback = $question->feedbackfalse; + if (!$false->id = insert_record("quiz_answers", $false)) { + $result->error = "Could not insert quiz answer \"false\")!"; + return $result; + } + + unset($options); + $options->question = $question->id; + $options->trueanswer = $true->id; + $options->falseanswer = $false->id; + if (!insert_record("quiz_truefalse", $options)) { + $result->error = "Could not insert quiz truefalse options!"; + return $result; + } + break; + case MULTICHOICE: + // FIXME - instead of deleting, update existing answers + // so as not to break existing references to them + delete_records("quiz_answers", "question", $question->id); + delete_records("quiz_multichoice", "question", $question->id); + + $totalfraction = 0; + $maxfraction = -1; + + $answers = array(); + + // Insert all the new answers + foreach ($question->answer as $key => $dataanswer) { + if ($dataanswer != "") { + unset($answer); + $answer->answer = $dataanswer; + $answer->question = $question->id; + $answer->fraction = $question->fraction[$key]; + $answer->feedback = $question->feedback[$key]; + if (!$answer->id = insert_record("quiz_answers", $answer)) { + $result->error = "Could not insert quiz answer!"; + return $result; + } + $answers[] = $answer->id; + + if ($question->fraction[$key] > 0) { // Sanity checks + $totalfraction += $question->fraction[$key]; + } + if ($question->fraction[$key] > $maxfraction) { + $maxfraction = $question->fraction[$key]; + } + } + } + + unset($options); + $options->question = $question->id; + $options->answers = implode(",",$answers); + $options->single = $question->single; + if (!insert_record("quiz_multichoice", $options)) { + $result->error = "Could not insert quiz multichoice options!"; + return $result; + } + + /// Perform sanity checks on fractional grades + if ($options->single) { + if ($maxfraction != 1) { + $maxfraction = $maxfraction * 100; + $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); + return $result; + } + } else { + $totalfraction = round($totalfraction,2); + if ($totalfraction != 1) { + $totalfraction = $totalfraction * 100; + $result->notice = get_string("fractionsaddwrong", "quiz", $totalfraction); + return $result; + } + } + break; + default: + $result->error = "Unsupported question type ($question->qtype)!"; + return $result; + break; + } + return true; +} + + ?> diff --git a/mod/quiz/question.php b/mod/quiz/question.php index a27873274d..7cd5df1afd 100644 --- a/mod/quiz/question.php +++ b/mod/quiz/question.php @@ -34,7 +34,7 @@ } $question->category = $category->id; - $question->qtype = $qtype; + $question->qtype = $qtype; } else { error("Must specify question id or category"); @@ -97,16 +97,20 @@ if ($form = data_submitted()) { // First, save the basic question itself + $question->name = $form->name; $question->questiontext = $form->questiontext; + if (empty($form->image)) { $question->image = ""; } else { $question->image = $form->image; } - $question->category = $form->category; - if (!$err = formcheck($question)) { + if ($err = formcheck($question)) { + notify(get_string("someerrorswerefound")); + + } else { if (!empty($question->id)) { // Question already exists if (!update_record("quiz_questions", $question)) { @@ -119,147 +123,21 @@ } // Now to save all the answers and type-specific options - - switch ($question->qtype) { - case SHORTANSWER: - // Delete all the old answers - // FIXME - instead of deleting, update existing answers - // so as not to break existing references to them - delete_records("quiz_answers", "question", $question->id); - delete_records("quiz_shortanswer", "question", $question->id); - - $answers = array(); - $maxfraction = -1; - - // Insert all the new answers - foreach ($form->answer as $key => $formanswer) { - if ($formanswer != "") { - unset($answer); - $answer->answer = $formanswer; - $answer->question = $question->id; - $answer->fraction = $fraction[$key]; - $answer->feedback = $feedback[$key]; - if (!$answer->id = insert_record("quiz_answers", $answer)) { - error("Could not insert quiz answer!"); - } - $answers[] = $answer->id; - if ($fraction[$key] > $maxfraction) { - $maxfraction = $fraction[$key]; - } - } - } - - unset($options); - $options->question = $question->id; - $options->answers = implode(",",$answers); - $options->usecase = $form->usecase; - if (!insert_record("quiz_shortanswer", $options)) { - error("Could not insert quiz shortanswer options!"); - } - - /// Perform sanity checks on fractional grades - if ($maxfraction != 1) { - $maxfraction = $maxfraction * 100; - notice_yesno(get_string("fractionsnomax", "quiz", $maxfraction), "question.php?id=$question->id", "edit.php"); - print_footer($course); - exit; - } - break; - case TRUEFALSE: - // FIXME - instead of deleting, update existing answers - // so as not to break existing references to them - delete_records("quiz_answers", "question", $question->id); - delete_records("quiz_truefalse", "question", $question->id); - - $true->answer = get_string("true", "quiz"); - $true->question = $question->id; - $true->fraction = $form->answer; - $true->feedback = $form->feedbacktrue; - if (!$true->id = insert_record("quiz_answers", $true)) { - error("Could not insert quiz answer \"true\")!"); - } - - $false->answer = get_string("false", "quiz"); - $false->question = $question->id; - $false->fraction = 1 - (int)$form->answer; - $false->feedback = $form->feedbackfalse; - if (!$false->id = insert_record("quiz_answers", $false)) { - error("Could not insert quiz answer \"false\")!"); - } - - unset($options); - $options->question = $question->id; - $options->trueanswer = $true->id; - $options->falseanswer = $false->id; - if (!insert_record("quiz_truefalse", $options)) { - error("Could not insert quiz truefalse options!"); - } - break; - case MULTICHOICE: - // FIXME - instead of deleting, update existing answers - // so as not to break existing references to them - delete_records("quiz_answers", "question", $question->id); - delete_records("quiz_multichoice", "question", $question->id); - - $totalfraction = 0; - $maxfraction = -1; - - $answers = array(); - - // Insert all the new answers - foreach ($form->answer as $key => $formanswer) { - if ($formanswer != "") { - unset($answer); - $answer->answer = $formanswer; - $answer->question = $question->id; - $answer->fraction = $fraction[$key]; - $answer->feedback = $feedback[$key]; - if (!$answer->id = insert_record("quiz_answers", $answer)) { - error("Could not insert quiz answer!"); - } - $answers[] = $answer->id; - - if ($fraction[$key] > 0) { // Sanity checks - $totalfraction += $fraction[$key]; - } - if ($fraction[$key] > $maxfraction) { - $maxfraction = $fraction[$key]; - } - } - } - - unset($options); - $options->question = $question->id; - $options->answers = implode(",",$answers); - $options->single = $form->single; - if (!insert_record("quiz_multichoice", $options)) { - error("Could not insert quiz multichoice options!"); - } - - /// Perform sanity checks on fractional grades - if ($options->single) { - if ($maxfraction != 1) { - $maxfraction = $maxfraction * 100; - notice_yesno(get_string("fractionsnomax", "quiz", $maxfraction), "question.php?id=$question->id", "edit.php"); - print_footer($course); - exit; - } - } else { - $totalfraction = round($totalfraction,2); - if ($totalfraction != 1) { - $totalfraction = $totalfraction * 100; - notice_yesno(get_string("fractionsaddwrong", "quiz", $totalfraction), "question.php?id=$question->id", "edit.php"); - print_footer($course); - exit; - } - } - break; - case RANDOM: - echo "<P>Not supported yet</P>"; - break; - default: - error("Non-existent question type!"); - break; + + $form->id = $question->id; + $form->qtype = $question->qtype; + $form->category = $question->category; + + $result = quiz_save_question_options($form); + + if (!empty($result->error)) { + error($result->error); + } + + if (!empty($result->notice)) { + notice_yesno($result->notice, "question.php?id=$question->id", "edit.php"); + print_footer($course); + exit; } redirect("edit.php"); diff --git a/mod/quiz/version.php b/mod/quiz/version.php index 55847316e2..2c47acbdb5 100644 --- a/mod/quiz/version.php +++ b/mod/quiz/version.php @@ -5,7 +5,7 @@ // This fragment is called by moodle_needs_upgrading() and /admin/index.php //////////////////////////////////////////////////////////////////////////////// -$module->version = 2003010301; // The (date) version of this module +$module->version = 2003021600; // The (date) version of this module $module->cron = 0; // How often should cron check this module (seconds)? ?> -- 2.39.5