From 79cc2bf137c883d29403e4b2d47579b446308c4c Mon Sep 17 00:00:00 2001 From: tjhunt Date: Wed, 2 Jul 2008 09:14:56 +0000 Subject: [PATCH] MDL-15494 - No allowance for the possibility that something might go wrong when processing the response to a question. Backported from HEAD. --- lang/en_utf8/question.php | 1 + lib/questionlib.php | 10 +++++-- mod/quiz/attempt.php | 35 +++++++++++++++++++--- question/preview.php | 5 +++- question/type/description/questiontype.php | 1 + 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/lang/en_utf8/question.php b/lang/en_utf8/question.php index e622f0fc5ac..f3681b4a67e 100644 --- a/lang/en_utf8/question.php +++ b/lang/en_utf8/question.php @@ -37,6 +37,7 @@ $string['errorfilecannotbemoved'] = 'Error cannot move file $a.'; $string['errorfileschanged'] = 'Error files linked to from questions have changed since form was displayed.'; $string['errormanualgradeoutofrange'] = 'The grade $a->grade is not between 0 and $a->maxgrade for question $a->name. The score and comment have not been saved.'; $string['errormovingquestions'] = 'Error while moving questions with ids $a.'; +$string['errorprocessingresponses'] = 'An error occurred while processing your responses.'; $string['errorsavingcomment'] = 'Error saving the comment for question $a->name in the database.'; $string['errorupdatingattempt'] = 'Error updating attempt $a->id in the database.'; $string['exportcategory'] = 'Export category'; diff --git a/lib/questionlib.php b/lib/questionlib.php index 58de9dc1b2c..a61af11177a 100644 --- a/lib/questionlib.php +++ b/lib/questionlib.php @@ -1268,7 +1268,6 @@ function regrade_question_in_attempt($question, $attempt, $cmoptions, $verbose=f /** * Processes an array of student responses, grading and saving them as appropriate * -* @return boolean Indicates success/failure * @param object $question Full question object, passed by reference * @param object $state Full state object, passed by reference * @param object $action object with the fields ->responses which @@ -1279,6 +1278,7 @@ function regrade_question_in_attempt($question, $attempt, $cmoptions, $verbose=f * @param object $cmoptions * @param object $attempt The attempt is passed by reference so that * during grading its ->sumgrades field can be updated +* @return boolean Indicates success/failure */ function question_process_responses(&$question, &$state, $action, $cmoptions, &$attempt) { global $QTYPES; @@ -1339,7 +1339,9 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$ if (!question_isgradingevent($action->event)) { // Grade the response but don't update the overall grade - $QTYPES[$question->qtype]->grade_responses($question, $state, $cmoptions); + if (!$QTYPES[$question->qtype]->grade_responses($question, $state, $cmoptions)) { + return false; + } // Temporary hack because question types are not given enough control over what is going // on. Used by Opaque questions. @@ -1375,8 +1377,10 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$ // If we did not find a duplicate or if the attempt is closing, perform grading if ((!$sameresponses and QUESTION_EVENTDUPLICATE != $state->event) or QUESTION_EVENTCLOSE == $action->event) { + if (!$QTYPES[$question->qtype]->grade_responses($question, $state, $cmoptions)) { + return false; + } - $QTYPES[$question->qtype]->grade_responses($question, $state, $cmoptions); // Calculate overall grade using correct penalty method question_apply_penalty_and_timelimit($question, $state, $attempt, $cmoptions); } diff --git a/mod/quiz/attempt.php b/mod/quiz/attempt.php index cb2f6689229..1bd5de98f91 100644 --- a/mod/quiz/attempt.php +++ b/mod/quiz/attempt.php @@ -303,14 +303,27 @@ // Process each question in turn $questionidarray = explode(',', $questionids); + $success = true; foreach($questionidarray as $i) { if (!isset($actions[$i])) { $actions[$i]->responses = array('' => ''); $actions[$i]->event = QUESTION_EVENTOPEN; } $actions[$i]->timestamp = $timestamp; - question_process_responses($questions[$i], $states[$i], $actions[$i], $quiz, $attempt); - save_question_session($questions[$i], $states[$i]); + if (question_process_responses($questions[$i], $states[$i], $actions[$i], $quiz, $attempt)) { + save_question_session($questions[$i], $states[$i]); + } else { + $success = false; + } + } + + if (!$success) { + $pagebit = ''; + if ($page) { + $pagebit = '&page=' . $page; + } + print_error('errorprocessingresponses', 'question', + $CFG->wwwroot . '/mod/quiz/attempt.php?q=' . $quiz->id . $pagebit); } $attempt->timemodified = $timestamp; @@ -345,12 +358,26 @@ error('Could not restore question sessions'); } + $success = true; foreach($closequestions as $key => $question) { $action->event = QUESTION_EVENTCLOSE; $action->responses = $closestates[$key]->responses; $action->timestamp = $closestates[$key]->timestamp; - question_process_responses($question, $closestates[$key], $action, $quiz, $attempt); - save_question_session($question, $closestates[$key]); + + if (question_process_responses($question, $closestates[$key], $action, $quiz, $attempt)) { + save_question_session($question, $closestates[$key]); + } else { + $success = false; + } + } + + if (!$success) { + $pagebit = ''; + if ($page) { + $pagebit = '&page=' . $page; + } + print_error('errorprocessingresponses', 'question', + $CFG->wwwroot . '/mod/quiz/attempt.php?q=' . $quiz->id . $pagebit); } add_to_log($course->id, 'quiz', 'close attempt', diff --git a/question/preview.php b/question/preview.php index 489535489ba..e6b278e5566 100644 --- a/question/preview.php +++ b/question/preview.php @@ -163,7 +163,10 @@ $event = $finishattempt ? QUESTION_EVENTCLOSE : QUESTION_EVENTSUBMIT; if ($actions = question_extract_responses($questions, $form, $event)) { $actions[$id]->timestamp = 0; // We do not care about timelimits here - question_process_responses($questions[$id], $curstate, $actions[$id], $quiz, $attempt); + if (!question_process_responses($questions[$id], $curstate, $actions[$id], $quiz, $attempt)) { + unset($SESSION->quizpreview); + print_error('errorprocessingresponses', 'question', $url->out()); + } if (!$curstate->changed) { // Update the current state rather than creating a new one $historylength--; diff --git a/question/type/description/questiontype.php b/question/type/description/questiontype.php index 354d8637fe8..96394a4b650 100644 --- a/question/type/description/questiontype.php +++ b/question/type/description/questiontype.php @@ -87,6 +87,7 @@ class description_qtype extends default_questiontype { function grade_responses(&$question, &$state, $cmoptions) { $state->raw_grade = 0; $state->penalty = 0; + return true; } }