From ef0376f4ef19ec93635a26cec6cb161aef4d0505 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Wed, 11 Jan 2012 16:21:47 +0000 Subject: [PATCH] MDL-31095 quiz editing: only set quiz->grade to 0 if really necessary. It is only necessary when there are (non-preview) attempts. However, after making this change we have to ensure users cannot start attempts when ->grade > 0 and ->sumgrades = 0. Display ->grade on the order and paging tab of edit.php, so it is clear what is going on when you are using that tab. Finally, improve the error message a student gets if they try to start a quiz with no questions. --- mod/quiz/edit.php | 6 ++---- mod/quiz/editlib.php | 2 +- mod/quiz/lang/en/quiz.php | 2 ++ mod/quiz/locallib.php | 21 ++++++++++++++++++--- mod/quiz/startattempt.php | 10 +++++++--- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/mod/quiz/edit.php b/mod/quiz/edit.php index 257208e89a9..07db4397018 100644 --- a/mod/quiz/edit.php +++ b/mod/quiz/edit.php @@ -275,8 +275,8 @@ if (($deleteemptypage !== false) && confirm_sesskey()) { $remove = optional_param('remove', false, PARAM_INT); if (($remove = optional_param('remove', false, PARAM_INT)) && confirm_sesskey()) { quiz_remove_question($quiz, $remove); - quiz_update_sumgrades($quiz); quiz_delete_previews($quiz); + quiz_update_sumgrades($quiz); redirect($afteractionurl); } @@ -496,9 +496,7 @@ if ($quiz_reordertool) { quiz_print_status_bar($quiz); $tabindex = 0; -if (!$quiz_reordertool) { - quiz_print_grading_form($quiz, $thispageurl, $tabindex); -} +quiz_print_grading_form($quiz, $thispageurl, $tabindex); $notifystrings = array(); if ($quizhasattempts) { diff --git a/mod/quiz/editlib.php b/mod/quiz/editlib.php index 608e38e1027..ae234d55885 100644 --- a/mod/quiz/editlib.php +++ b/mod/quiz/editlib.php @@ -248,8 +248,8 @@ function quiz_add_page_break_after($layout, $questionid) { function quiz_save_new_layout($quiz) { global $DB; $DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id)); - quiz_update_sumgrades($quiz); quiz_delete_previews($quiz); + quiz_update_sumgrades($quiz); } /** diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php index 897a16d0741..528166a1b62 100644 --- a/mod/quiz/lang/en/quiz.php +++ b/mod/quiz/lang/en/quiz.php @@ -127,7 +127,9 @@ $string['cannotsavenumberofquestion'] = 'Could not save number of questions per $string['cannotsavequestion'] = 'Cannot save question list'; $string['cannotsetgrade'] = 'Could not set a new maximum grade for the quiz'; $string['cannotsetsumgrades'] = 'Failed to set sumgrades'; +$string['cannotstartgradesmismatch'] = 'Cannot start an attempt at this quiz. The quiz is supposed to be graded, but there are no questions in the quiz that are worth any marks.'; $string['cannotstartmissingquestion'] = 'Cannot start an attempt at this quiz. The quiz definition includes a question that does not exist.'; +$string['cannotstartnoquestions'] = 'Cannot start an attempt at this quiz. The quiz has not been set up yet. No questions have been added.'; $string['cannotwrite'] = 'Cannot write to export file ({$a})'; $string['caseno'] = 'No, case is unimportant'; $string['casesensitive'] = 'Case sensitivity'; diff --git a/mod/quiz/locallib.php b/mod/quiz/locallib.php index 7e10d16999d..c59b6634fe3 100644 --- a/mod/quiz/locallib.php +++ b/mod/quiz/locallib.php @@ -69,6 +69,11 @@ define('QUIZ_SHOW_TIME_BEFORE_DEADLINE', '3600'); function quiz_create_attempt($quiz, $attemptnumber, $lastattempt, $timenow, $ispreview = false) { global $USER; + if ($quiz->sumgrades < 0.000005 && $quiz->grade > 0.000005) { + throw new moodle_exception('cannotstartgradesmismatch', 'quiz', + new moodle_url('/mod/quiz/view.php', array('q' => $quiz->id))); + } + if ($attemptnumber == 1 || !$quiz->attemptonlast) { // We are not building on last attempt so create a new attempt. $attempt = new stdClass(); @@ -386,10 +391,13 @@ function quiz_has_feedback($quiz) { * the grading structure of the quiz is changed. For example if a question is * added or removed, or a question weight is changed. * + * You should call {@link quiz_delete_previews()} before you call this function. + * * @param object $quiz a quiz. */ function quiz_update_sumgrades($quiz) { global $DB; + $sql = 'UPDATE {quiz} SET sumgrades = COALESCE(( SELECT SUM(grade) @@ -399,13 +407,20 @@ function quiz_update_sumgrades($quiz) { WHERE id = ?'; $DB->execute($sql, array($quiz->id)); $quiz->sumgrades = $DB->get_field('quiz', 'sumgrades', array('id' => $quiz->id)); - if ($quiz->sumgrades < 0.000005 && quiz_clean_layout($quiz->questions, true)) { - // If there is at least one question in the quiz, and the sumgrades has been - // set to 0, then also set the maximum possible grade to 0. + + if ($quiz->sumgrades < 0.000005 && quiz_has_attempts($quiz->id)) { + // If the quiz has been attempted, and the sumgrades has been + // set to 0, then we must also set the maximum possible grade to 0, or + // we will get a divide by zero error. quiz_set_grade(0, $quiz); } } +/** + * Update the sumgrades field of the attempts at a quiz. + * + * @param object $quiz a quiz. + */ function quiz_update_all_attempt_sumgrades($quiz) { global $DB; $dm = new question_engine_data_mapper(); diff --git a/mod/quiz/startattempt.php b/mod/quiz/startattempt.php index c3e31d855cd..80b8c25c5f8 100644 --- a/mod/quiz/startattempt.php +++ b/mod/quiz/startattempt.php @@ -50,9 +50,13 @@ $PAGE->set_url($quizobj->view_url()); require_login($quizobj->get_courseid(), false, $quizobj->get_cm()); require_sesskey(); -// if no questions have been set up yet redirect to edit.php -if (!$quizobj->has_questions() && $quizobj->has_capability('mod/quiz:manage')) { - redirect($quizobj->edit_url()); +// if no questions have been set up yet redirect to edit.php or display an error. +if (!$quizobj->has_questions()) { + if ($quizobj->has_capability('mod/quiz:manage')) { + redirect($quizobj->edit_url()); + } else { + print_error('cannotstartnoquestions', 'quiz', $quizobj->view_url()); + } } // Create an object to manage all the other (non-roles) access rules.