From: thepurpleblob Date: Fri, 8 Sep 2006 10:27:48 +0000 (+0000) Subject: Merged from STABLE X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=04d677f2e9d0bf3ec8f31e4a391ecf7f5781472e;p=moodle.git Merged from STABLE --- diff --git a/question/format/blackboard_6/format.php b/question/format/blackboard_6/format.php index 1ae814c15e..37281cd326 100644 --- a/question/format/blackboard_6/format.php +++ b/question/format/blackboard_6/format.php @@ -1,864 +1,1021 @@ -libdir/xmlize.php"); - -class qformat_blackboard_6 extends qformat_default { - function provide_import() { - return true; - } - - - //Function to check and create the needed dir to unzip file to - function check_and_create_import_dir($unique_code) { - - global $CFG; - - $status = $this->check_dir_exists($CFG->dataroot."/temp",true); - if ($status) { - $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import",true); - } - if ($status) { - $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import/".$unique_code,true); - } - - return $status; - } - - function clean_temp_dir($dir='') { - // this needs to be reworked - - - // for now we will just say everything happened okay note that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import - return true; - - if ($dir == '') { - $dir = $this->temp_dir; - } - $slash = "/"; - - // Create arrays to store files and directories - $dir_files = array(); - $dir_subdirs = array(); - - // Make sure we can delete it - chmod($dir, 0777); - - if ((($handle = opendir($dir))) == FALSE) { - // The directory could not be opened - return false; - } - - // Loop through all directory entries, and construct two temporary arrays containing files and sub directories - while($entry = readdir($handle)) { - if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != ".") { - $dir_subdirs[] = $dir. $slash .$entry; - } - else if ($entry != ".." && $entry != ".") { - $dir_files[] = $dir. $slash .$entry; - } - } - - // Delete all files in the curent directory return false and halt if a file cannot be removed - for($i=0; $iclean_temp_dir($dir_subdirs[$i]) == FALSE) { - return false; - } - else { - if (rmdir($dir_subdirs[$i]) == FALSE) { - return false; - } - } - } - - // Close directory - closedir($handle); - if (rmdir($this->temp_dir) == FALSE) { - return false; - } - // Success, every thing is gone return true - return true; - } - - //Function to check if a directory exists and, optionally, create it - function check_dir_exists($dir,$create=false) { - - global $CFG; - - $status = true; - if(!is_dir($dir)) { - if (!$create) { - $status = false; - } else { - umask(0000); - $status = mkdir ($dir,$CFG->directorypermissions); - } - } - return $status; - } - - function importpostprocess() { - /// Does any post-processing that may be desired - /// Argument is a simple array of question ids that - /// have just been added. - - // need to clean up temporary directory - return $this->clean_temp_dir(); - } - - function copy_file_to_course($filename) { - global $CFG; - global $course; - $filename = str_replace('\\','/',$filename); - $fullpath = $this->temp_dir.'/res00001/'.$filename; - $basename = basename($filename); - - $copy_to = $CFG->dataroot.'/'.$course->id.'/bb_import'; - - if ($this->check_dir_exists($copy_to,true)) { - if(is_readable($fullpath)) { - $copy_to.= '/'.$basename; - if (!copy($fullpath, $copy_to)) { - return false; - } - else { - return $copy_to; - } - } - } - else { - return false; - } - } - - function readdata($filename) { - /// Returns complete file with an array, one item per line - global $CFG; - - $unique_code = time(); - $temp_dir = $CFG->dataroot."/temp/bbquiz_import/".$unique_code; - $this->temp_dir = $temp_dir; - if ($this->check_and_create_import_dir($unique_code)) { - if(is_readable($filename)) { - if (!copy($filename, "$temp_dir/bboard.zip")) { - error("Could not copy backup file"); - } - if(unzip_file("$temp_dir/bboard.zip", '', false)) { - // assuming that the information is in res0001.dat - // after looking at 6 examples this was always the case - $q_file = "$temp_dir/res00001.dat"; - if (is_file($q_file)) { - if (is_readable($q_file)) { - $filearray = file($q_file); - /// Check for Macintosh OS line returns (ie file on one line), and fix - if (ereg("\r", $filearray[0]) AND !ereg("\n", $filearray[0])) { - return explode("\r", $filearray[0]); - } else { - return $filearray; - } - return false; - } - } - else { - error("Could not find question data file in zip"); - } - } - else { - print "filename: $filename
tempdir: $temp_dir
"; - error("Could not unzip file."); - } - } - else { - error ("Could not read uploaded file"); - } - } - else { - error("Could not create temporary directory"); - } - } - - function save_question_options($question) { - return true; - } - - - - function readquestions ($lines) { - /// Parses an array of lines into an array of questions, - /// where each item is a question object as defined by - /// readquestion(). - - $text = implode($lines, " "); - $xml = xmlize($text, 0); - - $raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item']; - $questions = array(); - - foreach($raw_questions as $quest) { - $question = $this->create_raw_question($quest); - switch($question->qtype) { - case "Matching": - $this->process_matching($question, $questions); - break; - case "Multiple Choice": - $this->process_mc($question, $questions); - break; - case "Essay": - $this->process_essay($question, $questions); - break; - case "Multiple Answer": - $this->process_ma($question, $questions); - break; - case "True/False": - $this->process_tf($question, $questions); - break; - case 'Fill in the Blank': - $this->process_fblank($question, $questions); - break; - default: - print "Unknown or unhandled question type: \"$question->qtype\"
"; - break; - } - - } - //print_object($questions); - return $questions; - } - - -// creates a cleaner object to deal with for processing into moodle -// the object created is NOT a moodle question object -function create_raw_question($quest) { - //print_object($quest); - $question = $this->defaultquestion(); - $question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#']; - $presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow']; - foreach($presentation->blocks as $pblock) { - - $block = NULL; - $block->type = $pblock['@']['class']; - switch($block->type) { - case 'QUESTION_BLOCK': - $sub_blocks = $pblock['#']['flow']; - foreach($sub_blocks as $sblock) { - $this->process_block($sblock, $block); - } - break; - case 'RESPONSE_BLOCK': - $choices = NULL; - switch($question->qtype) { - case 'Matching': - $bb_subquestions = $pblock['#']['flow']; - $sub_questions = array(); - foreach($bb_subquestions as $bb_subquestion) { - $sub_question = NULL; - $sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident']; - $this->process_block($bb_subquestion['#']['flow'][0], $sub_question); - $bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label']; - $choices = array(); - $this->process_choices($bb_choices, $choices); - $sub_question->choices = $choices; - if (!isset($block->subquestions)) { - $block->subquestions = array(); - } - $block->subquestions[] = $sub_question; - } - break; - case 'Multiple Answer': - $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label']; - $choices = array(); - $this->process_choices($bb_choices, $choices); - $block->choices = $choices; - break; - case 'Essay': - // Doesn't apply since the user responds with text input - break; - case 'Multiple Choice': - $mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label']; - foreach($mc_choices as $mc_choice) { - $choices = NULL; - $this->process_block($mc_choice, $choices); - $block->choices[] = $choices; - } - break; - case 'Fill in the Blank': - // do nothing? - break; - default: - $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label']; - $choices = array(); - $this->process_choices($bb_choices, $choices); - $block->choices = $choices; - } - break; - case 'RIGHT_MATCH_BLOCK': - $matching_answerset = $pblock['#']['flow']; - $answerset = array(); - foreach($matching_answerset as $answer) { - $this->process_block($answer, $bb_answer); - $answerset[] = $bb_answer; - } - $block->matching_answerset = $answerset; - break; - default: - print "UNHANDLED PRESENTATION BLOCK"; - break; - } - $question->{$block->type} = $block; - } - - // determine response processing - // there is a section called 'outcomes' that I don't know what to do with - $resprocessing = $quest['#']['resprocessing']; - - $respconditions = $resprocessing[0]['#']['respcondition']; - $reponses = array(); - if ($question->qtype == 'Matching') { - $this->process_matching_responses($respconditions, $responses); - } - else { - $this->process_responses($respconditions, $responses); - } - $question->responses = $responses; - - $feedbackset = $quest['#']['itemfeedback']; - - $feedbacks = array(); - $this->process_feedback($feedbackset, $feedbacks); - $question->feedback = $feedbacks; - - return $question; -} - -function process_block($cur_block, &$block) { - $cur_type = $cur_block['@']['class']; - global $course, $CFG; - switch($cur_type) { - case 'FORMATTED_TEXT_BLOCK': - $block->text = $this->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']); - break; - case 'FILE_BLOCK': - //revisit this to make sure it is working correctly - $block->file = $cur_block['#']['material'][0]['#']['matapplication'][0]['@']['uri']; - if ($block->file != '') { - // if we have a file copy it to the course dir and adjust its name to be visible over the web. - $block->file = $this->copy_file_to_course($block->file); - $block->file = $CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($block->file); - } - break; - case 'Block': - if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) { - $block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#']; - } - else if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) { - $block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']; - } - else if (isset($cur_block['#']['response_label'])) { - // this is a response label block - $sub_blocks = $cur_block['#']['response_label'][0]; - if(!isset($block->ident)) { - if(isset($sub_blocks['@']['ident'])) { - $block->ident = $sub_blocks['@']['ident']; - } - } - foreach($sub_blocks['#']['flow_mat'] as $sub_block) { - $this->process_block($sub_block, $block); - } - } - else { - if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) { - if (isset($cur_block['#']['flow_mat'])) { - $sub_blocks = $cur_block['#']['flow_mat']; - } - elseif (isset($cur_block['#']['flow'])) { - $sub_blocks = $cur_block['#']['flow']; - } - foreach ($sub_blocks as $sblock) { - // this will recursively grab the sub blocks which should be of one of the other types - $this->process_block($sblock, $block); - } - } - } - break; - case 'LINK_BLOCK': - // not sure how this should be included - if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) { - $block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri']; - } - else { - $block->link = ''; - } - break; - } -} - -function process_choices($bb_choices, &$choices) { - foreach($bb_choices as $choice) { - if (isset($choice['@']['ident'])) { - $cur_choice = $choice['@']['ident']; - } - else { - $cur_choice = $choice['#']['response_label'][0]['@']['ident']; - } - if (isset($choice['#']['flow_mat'][0])) { - $cur_block = $choice['#']['flow_mat'][0]; - $this->process_block($cur_block, $cur_choice); - } - elseif (isset($choice['#']['response_label'])) { - $this->process_block($choice, $cur_choice); - } - $choices[] = $cur_choice; - } -} - -function process_matching_responses($bb_responses, &$responses) { - //print_object($bb_responses); - foreach($bb_responses as $bb_response) { - $response = NULL; - if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) { - $response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#']; - $response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident']; - } - else { - $response->correct = 'Broken Question?'; - $response->ident = 'Broken Question?'; - } - $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid']; - $responses[] = $response; - } -} - -function process_responses($bb_responses, &$responses) { - foreach($bb_responses as $bb_response) { - if (isset($bb_response['@']['title'])) { - $response->title = $bb_response['@']['title']; - } - else { - $reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid']; - } - $reponse->ident = array(); - if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'])) { - $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#']; - } - else if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) { - $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#']; - } - - if (isset($bb_response['#']['conditionvar'][0]['#']['and'][0]['#'])) { - $responseset = $bb_response['#']['conditionvar'][0]['#']['and'][0]['#']['varequal']; - foreach($responseset as $rs) { - $response->ident[] = $rs['#']; - if(!isset($response->feedback)) { - $response->feedback = $rs['@']['respident']; - } - } - } - else { - $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid']; - } - - // determine what point value to give response - if (isset($bb_response['#']['setvar'])) { - switch ($bb_response['#']['setvar'][0]['#']) { - case "SCORE.max": - $response->fraction = 1; - break; - default: - // I have only seen this being 0 or unset there are probably fractional values of SCORE.max, but I'm not sure what they look like - $response->fraction = 0; - break; - } - } - else { - // just going to assume this is the case this is probably not correct. - $response->fraction = 0; - } - - - $responses[] = $response; - } -} - -function process_feedback($feedbackset, &$feedbacks) { - foreach($feedbackset as $bb_feedback) { - $feedback->ident = $bb_feedback['@']['ident']; - if (isset($bb_feedback['#']['flow_mat'][0])) { - $this->process_block($bb_feedback['#']['flow_mat'][0], $feedback); - } - elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) { - $this->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback); - } - $feedbacks[] = $feedback; - } -} - -//---------------------------------------- -// Process True / False Questions -//---------------------------------------- -function process_tf($quest, &$questions) { - $question = $this->defaultquestion(); - - $question->qtype = TRUEFALSE; - $question->defaultgrade = 1; - $question->single = 1; // Only one answer is allowed - $question->image = ""; // No images with this format - $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); - // put name in question object - $question->name = $question->questiontext; - - // first choice is true, second is false. - if ($quest->responses[0]->fraction == 1) { - $correct = true; - } - else { - $correct = false; - } - - foreach($quest->feedback as $fb) { - $fback->{$fb->ident} = $fb->text; - } - - if ($correct) { // true is correct - $question->answer = 1; - $question->feedbacktrue = addslashes($fback->correct); - $question->feedbackfalse = addslashes($fback->incorrect); - } else { // false is correct - $question->answer = 0; - $question->feedbacktrue = addslashes($fback->incorrect); - $question->feedbackfalse = addslashes($fback->correct); - } - $questions[] = $question; -} - - -//---------------------------------------- -// Process Fill in the Blank -//---------------------------------------- -function process_fblank($quest, &$questions) { - $question = $this->defaultquestion(); - $question->qtype = SHORTANSWER; - $question->defaultgrade = 1; - $question->single = 1; - $question->usecase = 0; - $question->image = ''; - $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); - $question->name = $question->questiontext; - $answers = array(); - $fractions = array(); - $feedbacks = array(); - - // extract the feedback - $feedback = array(); - foreach($quest->feedback as $fback) { - if (isset($fback->ident)) { - $feedback[$fback->ident] = $fback->text; - } - } - - foreach($quest->responses as $response) { - if(isset($response->title)) { - $answers[] = addslashes($response->ident[0]); - $fractions[] = $response->fraction; - if (isset($feedback[$response->feedback])) { - $feedbacks[] = addslashes($feedback[$response->feedback]); - } - else { - $feedbacks[] = ''; - } - } - } - - $question->answer = $answers; - $question->fraction = $fractions; - $question->feedback = $feedback; - - if (isset($question) && $question != '') { - $questions[] = $question; - } - -} - -//---------------------------------------- -// Process Multiple Choice Questions -//---------------------------------------- -function process_mc($quest, &$questions) { - $question = $this->defaultquestion(); - $question->qtype = MULTICHOICE; - $question->defaultgrade = 1; - $question->single = 1; - $question->image = ""; - $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); - $question->name = $question->questiontext; - - $feedback = array(); - foreach($quest->feedback as $fback) { - $feedback[$fback->ident] = addslashes($fback->text); - } - - - foreach($quest->responses as $response) { - if (isset($response->title)) { - if ($response->title == 'correct') { - // only one answer possible for this qtype so first index is correct answer - $correct = $response->ident[0]; - } - } - else { - // fallback method for when the title is not set - if ($response->feedback == 'correct') { - // only one answer possible for this qtype so first index is correct answer - $correct = $response->ident[0]; - } - } - } - - $i = 0; - foreach($quest->RESPONSE_BLOCK->choices as $response) { - $question->answer[$i] = addslashes($response->text); - if ($correct == $response->ident) { - $question->fraction[$i] = 1; - // this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists - // then specific feedback for this question (maybe this should be switched?, but from my example - // question pools I have not seen response specific feedback, only correct or incorrect feedback - if (!empty($feedback['correct'])) { - $question->feedback[$i] = $feedback['correct']; - } - elseif (!empty($feedback[$i])) { - $question->feedback[$i] = $feedback[$i]; - } - else { - // failsafe feedback (should be '' instead?) - $question->feedback[$i] = "correct"; - } - } - else { - $question->fraction[$i] = 0; - if (!empty($feedback['incorrect'])) { - $question->feedback[$i] = $feedback['incorrect']; - } - elseif (!empty($feedback[$i])) { - $question->feedback[$i] = $feedback[$i]; - } - else { - // failsafe feedback (should be '' instead?) - $question->feedback[$i] = 'incorrect'; - } - } - $i++; - } - - if (isset($question) && $question != '') { - $questions[] = $question; - } -} - -//---------------------------------------- -// Process Multiple Choice Questions With Multiple Answers -//---------------------------------------- -function process_ma($quest, &$questions) { - - $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); - $question->name = $question->questiontext; - $question->qtype = MULTICHOICE; - $question->defaultgrade = 1; - $question->single = 0; // More than one answers allowed - $question->image = ""; // No images with this format - - $answers = $quest->responses; - $correct_answers = array(); - foreach($answers as $answer) { - if($answer->title == 'correct') { - $answerset = $answer->ident; - foreach($answerset as $ans) { - $correct_answers[] = $ans; - } - } - } - - foreach ($quest->feedback as $fb) { - $feedback->{$fb->ident} = addslashes(trim($fb->text)); - } - - $correct_answer_count = count($correct_answers); - $choiceset = $quest->RESPONSE_BLOCK->choices; - $i = 0; - foreach($choiceset as $choice) { - $question->answer[$i] = addslashes(trim($choice->text)); - if (in_array($choice->ident, $correct_answers)) { - // correct answer - $question->fraction[$i] = floor(100000/$correct_answer_count)/100000; // strange behavior if we have more than 5 decimal places - $question->feedback[$i] = $feedback->correct; - } - else { - // wrong answer - $question->fraction[$i] = 0; - $question->feedback[$i] = $feedback->incorrect; - } - $i++; - } - - $questions[] = $question; -} - -//---------------------------------------- -// Process Essay Questions -//---------------------------------------- -function process_essay($quest, &$questions) { -// this should be rewritten to accomodate moodle 1.6 essay question type eventually - if (defined("ESSAY")) { - // treat as short answer - $question->qtype = ESSAY; - $question->defaultgrade = 1; - $question->usecase = 0; // Ignore case - $question->image = ""; // No images with this format - $question->questiontext = addslashes(trim($quest->QUESTION_BLOCK->text)); - $question->name = $question->questiontext; - - print $question->name; - - $question->answer = array(); - // not sure where to get the correct answer from - foreach($quest->feedback as $feedback) { - } - if (isset($question) && $question != '') { - $questions[]=$question; - } - } - else { - print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle
"; - print "    Omitted Question: ".$quest->QUESTION_BLOCK->text.'

'; - } -} - -//---------------------------------------- -// Process Matching Questions -//---------------------------------------- -function process_matching($quest, &$questions) { - if (defined("RENDEREDMATCH")) { - $question = $this->defaultquestion($this->defaultquestion()); - $question->valid = true; - $question->qtype = RENDEREDMATCH; - $question->defaultgrade = 1; - $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); - $question->name = $question->questiontext; - - foreach($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) { - foreach($quest->responses as $rid => $resp) { - if ($resp->ident == $subq->ident) { - $correct = addslashes($resp->correct); - $feedback = addslashes($resp->feedback); - } - } - - foreach($subq->choices as $cid => $choice) { - if ($choice == $correct) { - $question->subquestions[] = addslashes($subq->text); - $question->subanswers[] = addslashes($quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text); - } - } - } - - // check format - $status = true; - if ( count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) { - $status = false; - } - else { - // need to redo to make sure that no two questions have the same answer (rudimentary now) - foreach($question->subanswers as $qstn) { - if(isset($previous)) { - if ($qstn == $previous) { - $status = false; - } - } - $previous = $qstn; - if ($qstn == '') { - $status = false; - } - } - } - - if ($status) { - $questions[] = $question; - } - else { - global $course, $CFG; - print ''; - print ''; - - print ""; - print "'; - - print '
This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.
Question:".$quest->QUESTION_BLOCK->text; - if (isset($quest->QUESTION_BLOCK->file)) { - print '
There is a subfile contained in the zipfile that has been copied to course files: bb_import/'.basename($quest->QUESTION_BLOCK->file).''; - if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) { - print ''; - } - } - print "
Subquestions:
    "; - foreach($quest->responses as $rs) { - $correct_responses->{$rs->ident} = $rs->correct; - } - foreach($quest->RESPONSE_BLOCK->subquestions as $subq) { - print '
  • '.$subq->text.'
      '; - foreach($subq->choices as $id=>$choice) { - print '
    • '; - if ($choice == $correct_responses->{$subq->ident}) { - print ''; - } - else { - print ''; - } - print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text.'
    • '; - } - print '
    '; - } - print '
Feedback:
    '; - foreach($quest->feedback as $fb) { - print '
  • '.$fb->ident.': '.$fb->text.'
  • '; - } - print '
'; - } - } - else { - print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle
"; - print "    Omitted Question: ".$quest->QUESTION_BLOCK->text.'

'; - } -} - - -function strip_applet_tags_get_mathml($string) { - if(stristr($string, '') === FALSE) { - return $string; - } - else { - // strip all applet tags keeping stuff before/after and inbetween (if mathml) them - while (stristr($string, '') !== FALSE) { - preg_match("/(.*)\.*\<\/math\>)\".*\<\/applet\>(.*)/i",$string, $mathmls); - $string = $mathmls[1].$mathmls[2].$mathmls[3]; - } - return $string; - } -} - -} // close object -?> +libdir/xmlize.php"); + +class qformat_blackboard_6 extends qformat_default { + function provide_import() { + return true; + } + + + //Function to check and create the needed dir to unzip file to + function check_and_create_import_dir($unique_code) { + + global $CFG; + + $status = $this->check_dir_exists($CFG->dataroot."/temp",true); + if ($status) { + $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import",true); + } + if ($status) { + $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import/".$unique_code,true); + } + + return $status; + } + + function clean_temp_dir($dir='') { + // this needs to be reworked + + + // for now we will just say everything happened okay note that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import + return true; + + if ($dir == '') { + $dir = $this->temp_dir; + } + $slash = "/"; + + // Create arrays to store files and directories + $dir_files = array(); + $dir_subdirs = array(); + + // Make sure we can delete it + chmod($dir, 0777); + + if ((($handle = opendir($dir))) == FALSE) { + // The directory could not be opened + return false; + } + + // Loop through all directory entries, and construct two temporary arrays containing files and sub directories + while($entry = readdir($handle)) { + if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != ".") { + $dir_subdirs[] = $dir. $slash .$entry; + } + else if ($entry != ".." && $entry != ".") { + $dir_files[] = $dir. $slash .$entry; + } + } + + // Delete all files in the curent directory return false and halt if a file cannot be removed + for($i=0; $iclean_temp_dir($dir_subdirs[$i]) == FALSE) { + return false; + } + else { + if (rmdir($dir_subdirs[$i]) == FALSE) { + return false; + } + } + } + + // Close directory + closedir($handle); + if (rmdir($this->temp_dir) == FALSE) { + return false; + } + // Success, every thing is gone return true + return true; + } + + //Function to check if a directory exists and, optionally, create it + function check_dir_exists($dir,$create=false) { + + global $CFG; + + $status = true; + if(!is_dir($dir)) { + if (!$create) { + $status = false; + } else { + umask(0000); + $status = mkdir ($dir,$CFG->directorypermissions); + } + } + return $status; + } + + function importpostprocess() { + /// Does any post-processing that may be desired + /// Argument is a simple array of question ids that + /// have just been added. + + // need to clean up temporary directory + return $this->clean_temp_dir(); + } + + function copy_file_to_course($filename) { + global $CFG; + global $course; + $filename = str_replace('\\','/',$filename); + $fullpath = $this->temp_dir.'/res00001/'.$filename; + $basename = basename($filename); + + $copy_to = $CFG->dataroot.'/'.$course->id.'/bb_import'; + + if ($this->check_dir_exists($copy_to,true)) { + if(is_readable($fullpath)) { + $copy_to.= '/'.$basename; + if (!copy($fullpath, $copy_to)) { + return false; + } + else { + return $copy_to; + } + } + } + else { + return false; + } + } + + function readdata($filename) { + /// Returns complete file with an array, one item per line + global $CFG; + + $unique_code = time(); + $temp_dir = $CFG->dataroot."/temp/bbquiz_import/".$unique_code; + $this->temp_dir = $temp_dir; + if ($this->check_and_create_import_dir($unique_code)) { + if(is_readable($filename)) { + if (!copy($filename, "$temp_dir/bboard.zip")) { + error("Could not copy backup file"); + } + if(unzip_file("$temp_dir/bboard.zip", '', false)) { + // assuming that the information is in res0001.dat + // after looking at 6 examples this was always the case + $q_file = "$temp_dir/res00001.dat"; + if (is_file($q_file)) { + if (is_readable($q_file)) { + $filearray = file($q_file); + /// Check for Macintosh OS line returns (ie file on one line), and fix + if (ereg("\r", $filearray[0]) AND !ereg("\n", $filearray[0])) { + return explode("\r", $filearray[0]); + } else { + return $filearray; + } + return false; + } + } + else { + error("Could not find question data file in zip"); + } + } + else { + print "filename: $filename
tempdir: $temp_dir
"; + error("Could not unzip file."); + } + } + else { + error ("Could not read uploaded file"); + } + } + else { + error("Could not create temporary directory"); + } + } + + function save_question_options($question) { + return true; + } + + + + function readquestions ($lines) { + /// Parses an array of lines into an array of questions, + /// where each item is a question object as defined by + /// readquestion(). + + $text = implode($lines, " "); + $xml = xmlize($text, 0); + + $raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item']; + //echo "Line 213: Raw Questions
"; + //print_object($raw_questions); + $questions = array(); + + foreach($raw_questions as $quest) { + $question = $this->create_raw_question($quest); + + switch($question->qtype) { + case "Matching": + $this->process_matching($question, $questions); + break; + case "Multiple Choice": + $this->process_mc($question, $questions); + break; + case "Essay": + $this->process_essay($question, $questions); + break; + case "Multiple Answer": + $this->process_ma($question, $questions); + break; + case "True/False": + $this->process_tf($question, $questions); + break; + case 'Fill in the Blank': + $this->process_fblank($question, $questions); + break; + default: + print "Unknown or unhandled question type: \"$question->qtype\"
"; + break; + } + + } + //echo "readquestions:"; + //print_object ($questions); + return $questions; + } + + +// creates a cleaner object to deal with for processing into moodle +// the object created is NOT a moodle question object +function create_raw_question($quest) { + + $question = $this->defaultquestion(); + $question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#']; + $presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow']; + + foreach($presentation->blocks as $pblock) { + + $block = NULL; + $block->type = $pblock['@']['class']; + + switch($block->type) { + case 'QUESTION_BLOCK': + $sub_blocks = $pblock['#']['flow']; + foreach($sub_blocks as $sblock) { + //echo "Calling process_block from line 263
"; + $this->process_block($sblock, $block); + } + break; + + case 'RESPONSE_BLOCK': + $choices = NULL; + switch($question->qtype) { + case 'Matching': + $bb_subquestions = $pblock['#']['flow']; + $sub_questions = array(); + foreach($bb_subquestions as $bb_subquestion) { + $sub_question = NULL; + $sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident']; + //echo "Calling process_block from line 277
"; + $this->process_block($bb_subquestion['#']['flow'][0], $sub_question); + $bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label']; + $choices = array(); + $this->process_choices($bb_choices, $choices); + $sub_question->choices = $choices; + if (!isset($block->subquestions)) { + $block->subquestions = array(); + } + $block->subquestions[] = $sub_question; + } + break; + case 'Multiple Answer': + $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label']; + $choices = array(); + $this->process_choices($bb_choices, $choices); + $block->choices = $choices; + + break; + case 'Essay': + // Doesn't apply since the user responds with text input + break; + case 'Multiple Choice': + $mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label']; + + foreach($mc_choices as $mc_choice) { + $choices = NULL; + + + + //echo "Calling process_block from line 307
"; + $choices = $this->process_block($mc_choice, $choices); + $block->choices[] = $choices; + } + break; + case 'Fill in the Blank': + // do nothing? + break; + default: + $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label']; + $choices = array(); + $this->process_choices($bb_choices, $choices); + $block->choices = $choices; + } + break; + case 'RIGHT_MATCH_BLOCK': + $matching_answerset = $pblock['#']['flow']; + $answerset = array(); + foreach($matching_answerset as $answer) { + //echo "Calling process_block from line 235
"; + $this->process_block($answer, $bb_answer); + $answerset[] = $bb_answer; + } + $block->matching_answerset = $answerset; + break; + default: + print "UNHANDLED PRESENTATION BLOCK"; + break; + } + $question->{$block->type} = $block; + } + + // determine response processing + // there is a section called 'outcomes' that I don't know what to do with + $resprocessing = $quest['#']['resprocessing']; + + $respconditions = $resprocessing[0]['#']['respcondition']; + //echo "Line 347: respconditions
"; + //print_object ($respconditions); + + $reponses = array(); + if ($question->qtype == 'Matching') { + $this->process_matching_responses($respconditions, $responses); + } + else { + $this->process_responses($respconditions, $responses); + } + $question->responses = $responses; + + $feedbackset = $quest['#']['itemfeedback']; + + $feedbacks = array(); + + //echo "Line 362: Calling Process Feedback:
"; + $this->process_feedback($feedbackset, $feedbacks); + $question->feedback = $feedbacks; + + //echo "Line 358: "; + //print_object($question); + return $question; +} + +function process_block($cur_block, &$block) { + + $cur_type = $cur_block['@']['class']; + + global $course, $CFG; + switch($cur_type) { + case 'FORMATTED_TEXT_BLOCK': + $block->text = $this->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']); + //echo "Line 378: " . $block->text . '
'; + break; + case 'FILE_BLOCK': + //revisit this to make sure it is working correctly + + // Commented out ['matapplication']..., etc. because I noticed that when I imported a new Blackboard 6 file + // and printed out the block, the tree did not extend past ['material'][0]['#'] - CT 8/3/06 + $block->file = $cur_block['#']['material'][0]['#'];//['matapplication'][0]['@']['uri']; + if ($block->file != '') { + // if we have a file copy it to the course dir and adjust its name to be visible over the web. + $block->file = $this->copy_file_to_course($block->file); + $block->file = $CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($block->file); + } + break; + case 'Block': + + if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) { + $block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#']; + + //echo "line 379 - isset:" . isset($block->text); + //echo "Type: " . $cur_type . " Is Object:" . is_object($block) . "
\r\n"; + } + else if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) { + $block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']; + } + else if (isset($cur_block['#']['response_label'])) { + // this is a response label block + $sub_blocks = $cur_block['#']['response_label'][0]; + if(!isset($block->ident)) { + if(isset($sub_blocks['@']['ident'])) { + $block->ident = $sub_blocks['@']['ident']; + //echo "Line 409:
"; + //print_object($cur_block); + } + } + foreach($sub_blocks['#']['flow_mat'] as $sub_block) {\ + //echo "Calling process_block from line 404
"; + //$block = null; // Reset $block to NULL because process_block is expecting an object + // for the second argument and not a string, which is what is was set as + // originally + + $this->process_block($sub_block, $block); + } + } + else { + if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) { + if (isset($cur_block['#']['flow_mat'])) { + $sub_blocks = $cur_block['#']['flow_mat']; + } + elseif (isset($cur_block['#']['flow'])) { + $sub_blocks = $cur_block['#']['flow']; + } + foreach ($sub_blocks as $sblock) { + // this will recursively grab the sub blocks which should be of one of the other types + //echo "Calling process_block from line 419
"; + $this->process_block($sblock, $block); + } + } + } + break; + case 'LINK_BLOCK': + // not sure how this should be included + if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) { + $block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri']; + } + else { + $block->link = ''; + } + break; + } + //echo "Line 446: " . $block->text . '
'; + return $block; +} + +function process_choices($bb_choices, &$choices) { + + foreach($bb_choices as $choice) { + if (isset($choice['@']['ident'])) { + $cur_choice = $choice['@']['ident']; + } + else { //for multiple answer + $cur_choice = $choice['#']['response_label'][0];//['@']['ident']; + //echo "['#']['response_label'][0]['@']['ident']
\r\n"; + } + if (isset($choice['#']['flow_mat'][0])) { //for multiple answer + $cur_block = $choice['#']['flow_mat'][0]; + $cur_choice = null; // Reset $cur_choice to NULL because process_block is expecting an object + // for the second argument and not a string, which is what is was set as + // originally - CT 8/7/06 + //echo "Calling process_block from line 448
"; + $this->process_block($cur_block, $cur_choice); + } + elseif (isset($choice['#']['response_label'])) { + $cur_choice = null; // Reset $cur_choice to NULL because process_block is expecting an object + // for the second argument and not a string, which is what is was set as + // originally - CT 8/7/06 + //echo "Calling process_block from line 452
"; + $this->process_block($choice, $cur_choice); + } + $choices[] = $cur_choice; + } +} + +function process_matching_responses($bb_responses, &$responses) { + //echo "Line 486: Matching!
"; + //print_object($bb_responses); + foreach($bb_responses as $bb_response) { + $response = NULL; + if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) { + $response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#']; + $response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident']; + } + else { + $response->correct = 'Broken Question?'; + $response->ident = 'Broken Question?'; + } + $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid']; + $responses[] = $response; + } +} + +function process_responses($bb_responses, &$responses) { + + foreach($bb_responses as $bb_response) { + $response = null; //Added this line to instantiate $response. + // Without instantiating the $response variable, the same object + // gets added to the array + //echo "Line 504: bb_response
"; + //print_object ($bb_response); + + if (isset($bb_response['@']['title'])) { + $response->title = $bb_response['@']['title']; + } + else { + $reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid']; + } + $reponse->ident = array(); + if (isset($bb_response['#']['conditionvar'][0]['#'])){//['varequal'][0]['#'])) { + $response->ident[0] = $bb_response['#']['conditionvar'][0]['#'];//['varequal'][0]['#']; + } + else if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) { + $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#']; + } + + if (isset($bb_response['#']['conditionvar'][0]['#']['and'])){//[0]['#'])) { + $responseset = $bb_response['#']['conditionvar'][0]['#']['and'];//[0]['#']['varequal']; + foreach($responseset as $rs) { + $response->ident[] = $rs['#']; + if(!isset($response->feedback) and isset( $rs['@'] ) ) { + $response->feedback = $rs['@']['respident']; + } + } + } + else { + $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid']; + } + + // determine what point value to give response + if (isset($bb_response['#']['setvar'])) { + switch ($bb_response['#']['setvar'][0]['#']) { + case "SCORE.max": + $response->fraction = 1; + break; + default: + // I have only seen this being 0 or unset there are probably fractional values of SCORE.max, but I'm not sure what they look like + $response->fraction = 0; + break; + } + } + else { + // just going to assume this is the case this is probably not correct. + $response->fraction = 0; + } + + + + $responses[] = $response; + //echo "Line 554: $responses
"; + //print_object ($responses); + } +} + +function process_feedback($feedbackset, &$feedbacks) { + //echo "Line 551: In Process Feedback
"; + //echo "Line 552: feedbacks
"; + //print_object($feedbacks); + foreach($feedbackset as $bb_feedback) { + $feedback = null; // Added line $feedback=null so that $feedback does not get reused in the loop + // and added the the $feedbacks[] array multiple times + $feedback->ident = $bb_feedback['@']['ident']; + //echo "Line 558: " . $feedback->ident . "
\r\n"; + if (isset($bb_feedback['#']['flow_mat'][0])) { + //echo "Calling process_block from line 531
"; + $this->process_block($bb_feedback['#']['flow_mat'][0], $feedback); + + } + elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) { + //echo "Calling process_block from line 535
"; + $this->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback); + } + $feedbacks[] = $feedback; + + //echo "Line 568: feedbacks
"; + //print_object($feedbacks); + } + //echo "Line 571: feedbacks
"; + //print_object($feedbacks); + +} + +//---------------------------------------- +// Process True / False Questions +//---------------------------------------- +function process_tf($quest, &$questions) { + $question = $this->defaultquestion(); + + $question->qtype = TRUEFALSE; + $question->defaultgrade = 1; + $question->single = 1; // Only one answer is allowed + $question->image = ""; // No images with this format + $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); + // put name in question object + $question->name = $question->questiontext; + + // first choice is true, second is false. + if ($quest->responses[0]->fraction == 1) { + $correct = true; + } + else { + $correct = false; + } + + foreach($quest->feedback as $fb) { + $fback->{$fb->ident} = $fb->text; + } + + if ($correct) { // true is correct + $question->answer = 1; + $question->feedbacktrue = addslashes($fback->correct); + $question->feedbackfalse = addslashes($fback->incorrect); + } else { // false is correct + $question->answer = 0; + $question->feedbacktrue = addslashes($fback->incorrect); + $question->feedbackfalse = addslashes($fback->correct); + } + $questions[] = $question; +} + + +//---------------------------------------- +// Process Fill in the Blank +//---------------------------------------- +function process_fblank($quest, &$questions) { + + //echo "Line 633: Quest
"; + //print_object($quest); + + $question = $this->defaultquestion(); + $question->qtype = SHORTANSWER; + $question->defaultgrade = 1; + $question->single = 1; + $question->usecase = 0; + $question->image = ''; + $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); + $question->name = $question->questiontext; + $answers = array(); + $fractions = array(); + $feedbacks = array(); + + // extract the feedback + $feedback = array(); + foreach($quest->feedback as $fback) { + if (isset($fback->ident)) { + if ($fback->ident == 'correct' || $fback->ident == 'incorrect') + { + $feedback[$fback->ident] = $fback->text; + } + } + } + + foreach($quest->responses as $response) { + if(isset($response->title)) { + + if (isset($response->ident[0]['varequal'][0]['#'])) + { + //for BB Fill in the Blank, only interested in correct answers + if ($response->feedback = 'correct') + { + $answers[] = addslashes($response->ident[0]['varequal'][0]['#']); + $fractions[] = 1; + if (isset($feedback['correct'])) + { + $feedbacks[] = addslashes($feedback['correct']); + } + else + { + $feedbacks[] = ''; + } + } + } + + } + } + + //Adding catchall to so that students can see feedback for incorrect answers when they enter something the + //instructor did not enter + + $answers[] = '*'; + $fractions[] = 0; + if (isset($feedback['incorrect'])) + { + $feedbacks[] = addslashes($feedback['incorrect']); + } + else + { + $feedbacks[] = ''; + } + + $question->answer = $answers; + $question->fraction = $fractions; + $question->feedback = $feedbacks; // Changed to assign $feedbacks to $question->feedback instead of + // $feedback - CT 8/10/06 +// $question->feedback = $feedback; + + if (!empty($question)) { + $questions[] = $question; + } + +} + +//---------------------------------------- +// Process Multiple Choice Questions +//---------------------------------------- +function process_mc($quest, &$questions) { + //echo "Line 667: Quest
"; + //print_object($quest); + + $question = $this->defaultquestion(); + $question->qtype = MULTICHOICE; + $question->defaultgrade = 1; + $question->single = 1; + $question->image = ""; + $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); + $question->name = $question->questiontext; + + $feedback = array(); + foreach($quest->feedback as $fback) { + $feedback[$fback->ident] = addslashes($fback->text); + } + + //echo "Line 683: feedback
"; + //print_object($feedback); + + foreach($quest->responses as $response) { + + if (isset($response->title)) { + if ($response->title == 'correct') { + // only one answer possible for this qtype so first index is correct answer + $correct = $response->ident[0]['varequal'][0]['#']; // added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06 + } + } + else { + // fallback method for when the title is not set + if ($response->feedback == 'correct') { + // only one answer possible for this qtype so first index is correct answer + $correct = $response->ident[0]['varequal'][0]['#']; // added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06 + } + } + } + + //echo "Line 706: Correct:" . $correct . "
"; + + $i = 0; + foreach($quest->RESPONSE_BLOCK->choices as $response) { + + $question->answer[$i] = addslashes($response->text); + if ($correct == $response->ident) { + $question->fraction[$i] = 1; + // this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists + // then specific feedback for this question (maybe this should be switched?, but from my example + // question pools I have not seen response specific feedback, only correct or incorrect feedback + if (!empty($feedback['correct'])) { + $question->feedback[$i] = $feedback['correct']; + } + elseif (!empty($feedback[$i])) { + $question->feedback[$i] = $feedback[$i]; + } + else { + // failsafe feedback (should be '' instead?) + $question->feedback[$i] = "correct"; + } + } + else { + $question->fraction[$i] = 0; + if (!empty($feedback['incorrect'])) { + $question->feedback[$i] = $feedback['incorrect']; + } + elseif (!empty($feedback[$i])) { + $question->feedback[$i] = $feedback[$i]; + } + else { + // failsafe feedback (should be '' instead?) + $question->feedback[$i] = 'incorrect'; + } + } + $i++; + } + + if (!empty($question)) { + $questions[] = $question; + } +} + +//---------------------------------------- +// Process Multiple Choice Questions With Multiple Answers +//---------------------------------------- +function process_ma($quest, &$questions) { + + //echo "Line 763: Quest
"; + //print_object($quest); + + $question = $this->defaultquestion(); // copied this from process_mc + // noticed it was missing - CT 8/8/06 + $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); + $question->name = $question->questiontext; + $question->qtype = MULTICHOICE; + $question->defaultgrade = 1; + $question->single = 0; // More than one answer allowed + $question->image = ""; // No images with this format + + $answers = $quest->responses; + $correct_answers = array(); + foreach($answers as $answer) { + + //echo 'Line 779: $answer
'; + //print_object($answer); + if($answer->title == 'correct') { + $answerset = $answer->ident[0]['and'][0]['#']['varequal']; // added [0]['and'][0]['#']['varequal'] to $answer->ident - CT 8/9/06 + foreach($answerset as $ans) { + $correct_answers[] = $ans['#']; // added ['#'] to $ans - CT 8/9/06 + } + } + } + + foreach ($quest->feedback as $fb) { + $feedback->{$fb->ident} = addslashes(trim($fb->text)); + } + + $correct_answer_count = count($correct_answers); + $choiceset = $quest->RESPONSE_BLOCK->choices; + $i = 0; + foreach($choiceset as $choice) { + $question->answer[$i] = addslashes(trim($choice->text)); + if (in_array($choice->ident, $correct_answers)) { + // correct answer + $question->fraction[$i] = floor(100000/$correct_answer_count)/100000; // strange behavior if we have more than 5 decimal places + $question->feedback[$i] = $feedback->correct; + } + else { + // wrong answer + $question->fraction[$i] = 0; + $question->feedback[$i] = $feedback->incorrect; + } + $i++; + } + + $questions[] = $question; + //echo "Line 807: question
"; + //print_object($question); +} + +//---------------------------------------- +// Process Essay Questions +//---------------------------------------- +function process_essay($quest, &$questions) { +// this should be rewritten to accomodate moodle 1.6 essay question type eventually + + //echo "Line 822: Quest
"; + //print_object($quest); + + if (defined("ESSAY")) { + // treat as short answer + + $question = $this->defaultquestion(); // copied this from process_mc + // noticed it was missing - CT 8/8/06 + $question->qtype = ESSAY; + $question->defaultgrade = 1; + $question->usecase = 0; // Ignore case + $question->image = ""; // No images with this format + $question->questiontext = addslashes(trim($quest->QUESTION_BLOCK->text)); + $question->name = $question->questiontext; + + print $question->name; + + $question->feedback = array(); + // not sure where to get the correct answer from + foreach($quest->feedback as $feedback) { + + // Added this code to put the possible solution that the instructor gives as the Moodle answer for an essay question + // - CT 8/9/06 + if ($feedback->ident == 'solution') + { + $question->feedback = $feedback->text; + } + + + } + + $question->fraction[] = 1; //Added because essay/questiontype.php:save_question_option is expecting a + //fraction property - CT 8/10/06 + if (!empty($question)) { + $questions[]=$question; + } + + + } + else { + print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle
"; + print "    Omitted Question: ".$quest->QUESTION_BLOCK->text.'

'; + } +} + +//---------------------------------------- +// Process Matching Questions +//---------------------------------------- +function process_matching($quest, &$questions) { + + //echo "Line 910: Quest
"; + //print_object($quest); + + if (defined("RENDEREDMATCH")) { + $question = $this->defaultquestion($this->defaultquestion()); + $question->valid = true; + $question->qtype = RENDEREDMATCH; + $question->defaultgrade = 1; + $question->questiontext = addslashes($quest->QUESTION_BLOCK->text); + $question->name = $question->questiontext; + + foreach($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) { + foreach($quest->responses as $rid => $resp) { + if ($resp->ident == $subq->ident) { + $correct = addslashes($resp->correct); + $feedback = addslashes($resp->feedback); + } + } + + foreach($subq->choices as $cid => $choice) { + if ($choice == $correct) { + $question->subquestions[] = addslashes($subq->text); + $question->subanswers[] = addslashes($quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text); + } + } + } + + // check format + $status = true; + if ( count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) { + $status = false; + } + else { + // need to redo to make sure that no two questions have the same answer (rudimentary now) + foreach($question->subanswers as $qstn) { + if(isset($previous)) { + if ($qstn == $previous) { + $status = false; + } + } + $previous = $qstn; + if ($qstn == '') { + $status = false; + } + } + } + + if ($status) { + $questions[] = $question; + } + else { + global $course, $CFG; + print ''; + print ''; + + print ""; + print "'; + + print '
This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.
Question:".$quest->QUESTION_BLOCK->text; + if (isset($quest->QUESTION_BLOCK->file)) { + print '
There is a subfile contained in the zipfile that has been copied to course files: bb_import/'.basename($quest->QUESTION_BLOCK->file).''; + if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) { + print ''; + } + } + print "
Subquestions:
    "; + foreach($quest->responses as $rs) { + $correct_responses->{$rs->ident} = $rs->correct; + } + foreach($quest->RESPONSE_BLOCK->subquestions as $subq) { + print '
  • '.$subq->text.'
      '; + foreach($subq->choices as $id=>$choice) { + print '
    • '; + if ($choice == $correct_responses->{$subq->ident}) { + print ''; + } + else { + print ''; + } + print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text.'
    • '; + } + print '
    '; + } + print '
Feedback:
    '; + foreach($quest->feedback as $fb) { + print '
  • '.$fb->ident.': '.$fb->text.'
  • '; + } + print '
'; + } + } + else { + print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle
"; + print "    Omitted Question: ".$quest->QUESTION_BLOCK->text.'

'; + } +} + + +function strip_applet_tags_get_mathml($string) { + if(stristr($string, '') === FALSE) { + return $string; + } + else { + // strip all applet tags keeping stuff before/after and inbetween (if mathml) them + while (stristr($string, '') !== FALSE) { + preg_match("/(.*)\.*\<\/math\>)\".*\<\/applet\>(.*)/i",$string, $mathmls); + $string = $mathmls[1].$mathmls[2].$mathmls[3]; + } + return $string; + } +} + +} // close object +?>