diff --git a/mod/quiz/classes/external.php b/mod/quiz/classes/external.php index 235957805d3..2b7115573b7 100644 --- a/mod/quiz/classes/external.php +++ b/mod/quiz/classes/external.php @@ -863,6 +863,7 @@ class mod_quiz_external extends external_api { * * @return external_single_structure the question structure * @since Moodle 3.1 + * @since Moodle 3.2 blockedbyprevious parameter added. */ private static function question_structure() { return new external_single_structure( @@ -875,6 +876,8 @@ class mod_quiz_external extends external_api { 'number' => new external_value(PARAM_INT, 'question ordering number in the quiz', VALUE_OPTIONAL), 'state' => new external_value(PARAM_ALPHA, 'the state where the question is in', VALUE_OPTIONAL), 'status' => new external_value(PARAM_RAW, 'current formatted state of the question', VALUE_OPTIONAL), + 'blockedbyprevious' => new external_value(PARAM_BOOL, 'whether the question is blocked by the previous question', + VALUE_OPTIONAL), 'mark' => new external_value(PARAM_RAW, 'the mark awarded', VALUE_OPTIONAL), 'maxmark' => new external_value(PARAM_FLOAT, 'the maximum mark possible for this question attempt', VALUE_OPTIONAL), ) @@ -911,6 +914,7 @@ class mod_quiz_external extends external_api { $question['number'] = $attemptobj->get_question_number($slot); $question['state'] = (string) $attemptobj->get_question_state($slot); $question['status'] = $attemptobj->get_question_status($slot, $displayoptions->correctness); + $question['blockedbyprevious'] = $attemptobj->is_blocked_by_previous_question($slot); } if ($displayoptions->marks >= question_display_options::MAX_ONLY) { $question['maxmark'] = $attemptobj->get_question_attempt($slot)->get_max_mark(); diff --git a/mod/quiz/tests/external_test.php b/mod/quiz/tests/external_test.php index c106acae088..9aa209efa6d 100644 --- a/mod/quiz/tests/external_test.php +++ b/mod/quiz/tests/external_test.php @@ -104,14 +104,16 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase { * * @param boolean $startattempt whether to start a new attempt * @param boolean $finishattempt whether to finish the new attempt + * @param string $behaviour the quiz preferredbehaviour, defaults to 'deferredfeedback'. * @return array array containing the quiz, context and the attempt */ - private function create_quiz_with_questions($startattempt = false, $finishattempt = false) { + private function create_quiz_with_questions($startattempt = false, $finishattempt = false, $behaviour = 'deferredfeedback') { // Create a new quiz with attempts. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); $data = array('course' => $this->course->id, - 'sumgrades' => 2); + 'sumgrades' => 2, + 'preferredbehaviour' => $behaviour); $quiz = $quizgenerator->create_instance($data); $context = context_module::instance($quiz->cmid); @@ -929,6 +931,51 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase { } + /** + * Test get_attempt_data with blocked questions. + * @since 3.2 + */ + public function test_get_attempt_data_with_blocked_questions() { + global $DB; + + // Create a new quiz with one attempt started and using immediatefeedback. + list($quiz, $context, $quizobj, $attempt, $attemptobj) = $this->create_quiz_with_questions( + true, false, 'immediatefeedback'); + + $quizobj = $attemptobj->get_quizobj(); + + // Make second question blocked by the first one. + $structure = $quizobj->get_structure(); + $slots = $structure->get_slots(); + $structure->update_question_dependency(end($slots)->id, true); + + $quizobj->preload_questions(); + $quizobj->load_questions(); + $questions = $quizobj->get_questions(); + + $this->setUser($this->student); + + // We receive one question per page. + $result = mod_quiz_external::get_attempt_data($attempt->id, 0); + $result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_data_returns(), $result); + + $this->assertEquals($attempt, (object) $result['attempt']); + $this->assertCount(1, $result['questions']); + $this->assertEquals(1, $result['questions'][0]['slot']); + $this->assertEquals(1, $result['questions'][0]['number']); + $this->assertEquals(false, $result['questions'][0]['blockedbyprevious']); + + // Now try the last page. + $result = mod_quiz_external::get_attempt_data($attempt->id, 1); + $result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_data_returns(), $result); + + $this->assertEquals($attempt, (object) $result['attempt']); + $this->assertCount(1, $result['questions']); + $this->assertEquals(2, $result['questions'][0]['slot']); + $this->assertEquals(2, $result['questions'][0]['number']); + $this->assertEquals(true, $result['questions'][0]['blockedbyprevious']); + } + /** * Test get_attempt_summary */ diff --git a/mod/quiz/upgrade.txt b/mod/quiz/upgrade.txt index 299f877a8e3..3568c525c5a 100644 --- a/mod/quiz/upgrade.txt +++ b/mod/quiz/upgrade.txt @@ -1,5 +1,11 @@ This files describes API changes in the quiz code. +=== 3.2 === + +* External functions mod_quiz_external::get_attempt_data, mod_quiz_external::get_attempt_summary + and mod_quiz_external::get_attempt_review now return additional optional fields: + - blockedbyprevious: Whether a question is blocked by the previous question. + === 3.1 === * quiz_attempt::question_print_comment_fields() has been removed. It was broken