diff --git a/mod/quiz/classes/external.php b/mod/quiz/classes/external.php index a9926c80896..6cb38bc0817 100644 --- a/mod/quiz/classes/external.php +++ b/mod/quiz/classes/external.php @@ -859,7 +859,7 @@ class mod_quiz_external extends external_api { /** * Describes a single question structure. * - * @return external_single_structure the question structure + * @return external_single_structure the question data. Some fields may not be returned depending on the quiz display settings. * @since Moodle 3.1 */ private static function question_structure() { @@ -871,11 +871,16 @@ class mod_quiz_external extends external_api { 'html' => new external_value(PARAM_RAW, 'the question rendered'), 'flagged' => new external_value(PARAM_BOOL, 'whether the question is flagged or not'), '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), + 'state' => new external_value(PARAM_ALPHA, 'the state where the question is in. + It will not be returned if the user cannot see it due to the quiz display correctness settings.', + VALUE_OPTIONAL), 'status' => new external_value(PARAM_RAW, 'current formatted state of the 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), - ) + 'mark' => new external_value(PARAM_RAW, 'the mark awarded. + It will be returned only if the user is allowed to see it.', VALUE_OPTIONAL), + 'maxmark' => new external_value(PARAM_FLOAT, 'the maximum mark possible for this question attempt. + It will be returned only if the user is allowed to see it.', VALUE_OPTIONAL), + ), + 'The question data. Some fields may not be returned depending on the quiz display settings.' ); } @@ -907,7 +912,10 @@ class mod_quiz_external extends external_api { if ($attemptobj->is_real_question($slot)) { $question['number'] = $attemptobj->get_question_number($slot); - $question['state'] = (string) $attemptobj->get_question_state($slot); + $showcorrectness = $displayoptions->correctness && $attemptobj->get_question_attempt($slot)->has_marks(); + if ($showcorrectness) { + $question['state'] = (string) $attemptobj->get_question_state($slot); + } $question['status'] = $attemptobj->get_question_status($slot, $displayoptions->correctness); } if ($displayoptions->marks >= question_display_options::MAX_ONLY) { diff --git a/mod/quiz/tests/external_test.php b/mod/quiz/tests/external_test.php index 38b8681fe72..c693ea04074 100644 --- a/mod/quiz/tests/external_test.php +++ b/mod/quiz/tests/external_test.php @@ -850,6 +850,9 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase { // Create a new quiz with one attempt started. list($quiz, $context, $quizobj, $attempt, $attemptobj) = $this->create_quiz_with_questions(true); + // Set correctness mask so questions state can be fetched only after finishing the attempt. + $DB->set_field('quiz', 'reviewcorrectness', mod_quiz_display_options::IMMEDIATELY_AFTER, array('id' => $quiz->id)); + $quizobj = $attemptobj->get_quizobj(); $quizobj->preload_questions(); $quizobj->load_questions(); @@ -868,7 +871,7 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase { $this->assertEquals(1, $result['questions'][0]['slot']); $this->assertEquals(1, $result['questions'][0]['number']); $this->assertEquals('numerical', $result['questions'][0]['type']); - $this->assertEquals('todo', $result['questions'][0]['state']); + $this->assertArrayNotHasKey('state', $result['questions'][0]); // We don't receive the state yet. $this->assertEquals(get_string('notyetanswered', 'question'), $result['questions'][0]['status']); $this->assertFalse($result['questions'][0]['flagged']); $this->assertEquals(0, $result['questions'][0]['page']); @@ -886,7 +889,7 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase { $this->assertEquals(2, $result['questions'][0]['slot']); $this->assertEquals(2, $result['questions'][0]['number']); $this->assertEquals('numerical', $result['questions'][0]['type']); - $this->assertEquals('todo', $result['questions'][0]['state']); + $this->assertArrayNotHasKey('state', $result['questions'][0]); // We don't receive the state yet. $this->assertEquals(get_string('notyetanswered', 'question'), $result['questions'][0]['status']); $this->assertFalse($result['questions'][0]['flagged']); $this->assertEquals(1, $result['questions'][0]['page']); @@ -894,6 +897,11 @@ class mod_quiz_external_testcase extends externallib_advanced_testcase { // Finish previous attempt. $attemptobj->process_finish(time(), false); + // Now we should receive the question state. + $result = mod_quiz_external::get_attempt_review($attempt->id, 1); + $result = external_api::clean_returnvalue(mod_quiz_external::get_attempt_review_returns(), $result); + $this->assertEquals('gaveup', $result['questions'][0]['state']); + // Change setting and expect two pages. $quiz->questionsperpage = 4; $DB->update_record('quiz', $quiz);