diff --git a/mod/quiz/attemptlib.php b/mod/quiz/attemptlib.php index a713757fc6448..3dbbe75b0ac59 100644 --- a/mod/quiz/attemptlib.php +++ b/mod/quiz/attemptlib.php @@ -90,7 +90,12 @@ public function __construct($quiz, $cm, $course, $getcontext = true) { if ($getcontext && !empty($cm->id)) { $this->context = get_context_instance(CONTEXT_MODULE, $cm->id); } - $this->questionids = explode(',', quiz_questions_in_quiz($this->quiz->questions)); + $questionids = quiz_questions_in_quiz($this->quiz->questions); + if ($questionids) { + $this->questionids = explode(',', quiz_questions_in_quiz($this->quiz->questions)); + } else { + $this->questionids = array(); // Which idiot made explode(',', '') = array('')? + } } /** diff --git a/mod/quiz/edit.php b/mod/quiz/edit.php index eb1e658ddcb6b..1d4d665bc1b38 100644 --- a/mod/quiz/edit.php +++ b/mod/quiz/edit.php @@ -275,8 +275,8 @@ function module_specific_controls($totalnumber, $recurse, $category, $cmid, $cmo $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 @@ function module_specific_controls($totalnumber, $recurse, $category, $cmid, $cmo 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 5ee8b4b660f35..6294f16bc97be 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 897a16d07413f..528166a1b6247 100644 --- a/mod/quiz/lang/en/quiz.php +++ b/mod/quiz/lang/en/quiz.php @@ -127,7 +127,9 @@ $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 2d5d8e06b5dce..9682ca0dfad98 100644 --- a/mod/quiz/locallib.php +++ b/mod/quiz/locallib.php @@ -69,6 +69,11 @@ 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/simpletest/testquizobj.php b/mod/quiz/simpletest/testquizobj.php index 625e8d5187276..59e83fbb20958 100644 --- a/mod/quiz/simpletest/testquizobj.php +++ b/mod/quiz/simpletest/testquizobj.php @@ -64,4 +64,19 @@ public function test_cannot_review_message() { $this->assertEqual(get_string('noreviewuntil', 'quiz', userdate($closetime)), $quizobj->cannot_review_message(mod_quiz_display_options::LATER_WHILE_OPEN)); } + + public function test_empty_quiz() { + $quiz = new stdClass(); + $quiz->reviewattempt = 0x10010; + $quiz->timeclose = 0; + $quiz->attempts = 0; + $quiz->questions = '0'; + + $cm = new stdClass(); + $cm->id = 123; + + $quizobj = new quiz($quiz, $cm, new stdClass(), false); + + $this->assertFalse($quizobj->has_questions()); + } } diff --git a/mod/quiz/startattempt.php b/mod/quiz/startattempt.php index a9451237b97f2..57321937c44fd 100644 --- a/mod/quiz/startattempt.php +++ b/mod/quiz/startattempt.php @@ -50,9 +50,13 @@ 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.