diff --git a/mod/quiz/backup/moodle2/backup_quiz_stepslib.php b/mod/quiz/backup/moodle2/backup_quiz_stepslib.php
index a411cfd586d..151cb7de9c6 100644
--- a/mod/quiz/backup/moodle2/backup_quiz_stepslib.php
+++ b/mod/quiz/backup/moodle2/backup_quiz_stepslib.php
@@ -34,7 +34,7 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
'name', 'intro', 'introformat', 'timeopen', 'timeclose', 'timelimit',
'overduehandling', 'graceperiod', 'preferredbehaviour', 'canredoquestions', 'attempts_number',
'attemptonlast', 'grademethod', 'decimalpoints', 'questiondecimalpoints',
- 'reviewattempt', 'reviewcorrectness', 'reviewmarks',
+ 'reviewattempt', 'reviewcorrectness', 'reviewmaxmarks', 'reviewmarks',
'reviewspecificfeedback', 'reviewgeneralfeedback',
'reviewrightanswer', 'reviewoverallfeedback',
'questionsperpage', 'navmethod', 'shuffleanswers',
diff --git a/mod/quiz/backup/moodle2/restore_quiz_stepslib.php b/mod/quiz/backup/moodle2/restore_quiz_stepslib.php
index 5709815c788..d88f078f91c 100644
--- a/mod/quiz/backup/moodle2/restore_quiz_stepslib.php
+++ b/mod/quiz/backup/moodle2/restore_quiz_stepslib.php
@@ -184,6 +184,14 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
($oldreview & QUIZ_OLD_CLOSED & QUIZ_OLD_SCORES ?
display_options::AFTER_CLOSE : 0);
+ if (!isset($data->reviewmaxmarks)) {
+ $data->reviewmaxmarks =
+ display_options::DURING |
+ display_options::IMMEDIATELY_AFTER |
+ display_options::LATER_WHILE_OPEN |
+ display_options::AFTER_CLOSE;
+ }
+
$data->reviewmarks =
display_options::DURING |
($oldreview & QUIZ_OLD_IMMEDIATELY & QUIZ_OLD_SCORES ?
diff --git a/mod/quiz/classes/admin/review_setting.php b/mod/quiz/classes/admin/review_setting.php
index d22e2e108b9..f9a054cf002 100644
--- a/mod/quiz/classes/admin/review_setting.php
+++ b/mod/quiz/classes/admin/review_setting.php
@@ -63,6 +63,7 @@ class review_setting extends \admin_setting {
return [
'attempt' => get_string('theattempt', 'quiz'),
'correctness' => get_string('whethercorrect', 'question'),
+ 'maxmarks' => get_string('maxmarks', 'quiz'),
'marks' => get_string('marks', 'question'),
'specificfeedback' => get_string('specificfeedback', 'question'),
'generalfeedback' => get_string('generalfeedback', 'question'),
diff --git a/mod/quiz/classes/external.php b/mod/quiz/classes/external.php
index 8cae72c1ce3..d5b291f63e5 100644
--- a/mod/quiz/classes/external.php
+++ b/mod/quiz/classes/external.php
@@ -131,7 +131,7 @@ class mod_quiz_external extends external_api {
$quizdetails['hasquestions'] = (int) $quizobj->has_questions();
$quizdetails['autosaveperiod'] = get_config('quiz', 'autosaveperiod');
- $additionalfields = ['attemptonlast', 'reviewattempt', 'reviewcorrectness', 'reviewmarks',
+ $additionalfields = ['attemptonlast', 'reviewattempt', 'reviewcorrectness', 'reviewmaxmarks', 'reviewmarks',
'reviewspecificfeedback', 'reviewgeneralfeedback', 'reviewrightanswer',
'reviewoverallfeedback', 'questionsperpage', 'navmethod',
'browsersecurity', 'delay1', 'delay2', 'showuserpicture', 'showblocks',
@@ -208,8 +208,9 @@ class mod_quiz_external extends external_api {
\mod_quiz\question\display_options class. It is formed by ORing
together the constants defined there.', VALUE_OPTIONAL),
'reviewcorrectness' => new external_value(PARAM_INT, 'Whether users are allowed to review their quiz
- attempts at various times.
- A bit field, like reviewattempt.', VALUE_OPTIONAL),
+ attempts at various times.A bit field, like reviewattempt.', VALUE_OPTIONAL),
+ 'reviewmaxmarks' => new external_value(PARAM_INT, 'Whether users are allowed to review their quiz
+ attempts at various times. A bit field, like reviewattempt.', VALUE_OPTIONAL),
'reviewmarks' => new external_value(PARAM_INT, 'Whether users are allowed to review their quiz attempts
at various times. A bit field, like reviewattempt.',
VALUE_OPTIONAL),
diff --git a/mod/quiz/classes/question/display_options.php b/mod/quiz/classes/question/display_options.php
index 1e6d5d34a0a..b9904ff2796 100644
--- a/mod/quiz/classes/question/display_options.php
+++ b/mod/quiz/classes/question/display_options.php
@@ -72,8 +72,8 @@ class display_options extends \question_display_options {
$options->attempt = self::extract($quiz->reviewattempt, $when, true, false);
$options->correctness = self::extract($quiz->reviewcorrectness, $when);
- $options->marks = self::extract($quiz->reviewmarks, $when,
- self::MARK_AND_MAX, self::MAX_ONLY);
+ $options->marks = self::extract($quiz->reviewmaxmarks, $when,
+ self::extract($quiz->reviewmarks, $when, self::MARK_AND_MAX, self::MAX_ONLY), self::HIDDEN);
$options->feedback = self::extract($quiz->reviewspecificfeedback, $when);
$options->generalfeedback = self::extract($quiz->reviewgeneralfeedback, $when);
$options->rightanswer = self::extract($quiz->reviewrightanswer, $when);
diff --git a/mod/quiz/db/install.xml b/mod/quiz/db/install.xml
index a5e9f2474e0..0f78dc049a0 100644
--- a/mod/quiz/db/install.xml
+++ b/mod/quiz/db/install.xml
@@ -19,17 +19,18 @@
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/mod/quiz/db/upgrade.php b/mod/quiz/db/upgrade.php
index 02be52bd761..df41e5e297b 100644
--- a/mod/quiz/db/upgrade.php
+++ b/mod/quiz/db/upgrade.php
@@ -179,5 +179,20 @@ function xmldb_quiz_upgrade($oldversion) {
// Automatically generated Moodle v4.2.0 release upgrade line.
// Put any upgrade step following this.
+ if ($oldversion < 2023042401) {
+
+ // Define field reviewmaxmarks to be added to quiz.
+ $table = new xmldb_table('quiz');
+ $field = new xmldb_field('reviewmaxmarks', XMLDB_TYPE_INTEGER, '6', null, XMLDB_NOTNULL, null, '0', 'reviewcorrectness');
+
+ // Conditionally launch add field reviewmaxmarks.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ // Quiz savepoint reached.
+ upgrade_mod_savepoint(true, 2023042401, 'quiz');
+ }
+
return true;
}
diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php
index e5c24a60eab..98f3f531fda 100644
--- a/mod/quiz/lang/en/quiz.php
+++ b/mod/quiz/lang/en/quiz.php
@@ -532,6 +532,15 @@ $string['messageprovider:attempt_grading_complete'] = 'Notification that your at
$string['messageprovider:submission'] = 'Notification of your students\' quiz submissions';
$string['max'] = 'Max';
$string['maxmark'] = 'Maximum mark';
+$string['maxmarks'] = 'Max Marks';
+$string['maxmarks_help'] = 'Max marks determines whether the grade information are hidden or how it is displayed:
+
+* To hide the grade information completely, do not tick this checkbox (Marks checkbox is disabled automatically).
+
+* To show Max marks only: tick this checkbox and not the Marks checkbox.
+
+* To show both Max marks and Marks, tick this checkbox as well as the Marks checkbox.';
+
$string['min'] = 'Min';
$string['minutes'] = 'Minutes';
$string['missingcorrectanswer'] = 'Correct answer must be specified';
diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php
index 08841dd0730..f64b5f147d5 100644
--- a/mod/quiz/lib.php
+++ b/mod/quiz/lib.php
@@ -1117,6 +1117,7 @@ function quiz_process_options($quiz) {
// Combing the individual settings into the review columns.
$quiz->reviewattempt = quiz_review_option_form_to_db($quiz, 'attempt');
$quiz->reviewcorrectness = quiz_review_option_form_to_db($quiz, 'correctness');
+ $quiz->reviewmaxmarks = quiz_review_option_form_to_db($quiz, 'maxmarks');
$quiz->reviewmarks = quiz_review_option_form_to_db($quiz, 'marks');
$quiz->reviewspecificfeedback = quiz_review_option_form_to_db($quiz, 'specificfeedback');
$quiz->reviewgeneralfeedback = quiz_review_option_form_to_db($quiz, 'generalfeedback');
diff --git a/mod/quiz/mod_form.php b/mod/quiz/mod_form.php
index 44cff553ebd..cf91026c424 100644
--- a/mod/quiz/mod_form.php
+++ b/mod/quiz/mod_form.php
@@ -54,6 +54,7 @@ class mod_quiz_mod_form extends moodleform_mod {
self::$reviewfields = [
'attempt' => ['theattempt', 'quiz'],
'correctness' => ['whethercorrect', 'question'],
+ 'maxmarks' => ['maxmarks', 'quiz'],
'marks' => ['marks', 'quiz'],
'specificfeedback' => ['specificfeedback', 'question'],
'generalfeedback' => ['generalfeedback', 'question'],
@@ -403,6 +404,7 @@ class mod_quiz_mod_form extends moodleform_mod {
}
}
+ $mform->disabledIf('marks' . $whenname, 'maxmarks' . $whenname);
if ($whenname != 'during') {
$mform->disabledIf('correctness' . $whenname, 'attempt' . $whenname);
$mform->disabledIf('specificfeedback' . $whenname, 'attempt' . $whenname);
diff --git a/mod/quiz/tests/behat/attempt_review_options.feature b/mod/quiz/tests/behat/attempt_review_options.feature
new file mode 100644
index 00000000000..d33d45fb1d9
--- /dev/null
+++ b/mod/quiz/tests/behat/attempt_review_options.feature
@@ -0,0 +1,64 @@
+@mod @mod_quiz
+Feature: Allow settings to show Max marks and Marks, Max marks only, or hide the grade information completely.
+ As a teacher
+ In order to decide how grade review options are displayed on questions in a quiz review page
+ I need to be able to set the grade review options for a quiz to to show Max and Marks, Max only, or hide the grade information.
+
+ Background:
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | student1 | Student | One | student1@example.com |
+ | teacher | Teacher | One | teacher@example.com |
+ And the following "courses" exist:
+ | fullname | shortname | category |
+ | Course 1 | C1 | 0 |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher | C1 | editingteacher |
+ | student1 | C1 | student |
+ And the following "question categories" exist:
+ | contextlevel | reference | name |
+ | Course | C1 | Test questions |
+ And the following "questions" exist:
+ | questioncategory | qtype | name | questiontext |
+ | Test questions | truefalse | TF1 | First question |
+ And the following "activities" exist:
+ | activity | name | intro | course | idnumber | maxmarksduring | marksduring | maxmarksimmediately | marksimmediately | preferredbehaviour |
+ | quiz | Quiz 1 | Quiz 1 test | C1 | quiz1 | 1 | 1 | 1 | 1 | immediatefeedback |
+ | quiz | Quiz 2 | Quiz 2 test | C1 | quiz2 | 0 | 0 | 1 | 1 | immediatefeedback |
+ And quiz "Quiz 1" contains the following questions:
+ | question | page | maxmark |
+ | TF1 | 1 | 2.00 |
+ And quiz "Quiz 2" contains the following questions:
+ | question | page | maxmark |
+ | TF1 | 1 | 2.00 |
+
+ @javascript
+ Scenario: Show max marks and marks during and immediately after the attempt.
+ Given I am on the "Quiz 1" "quiz activity" page logged in as "student1"
+ And I click on "Attempt quiz" "button"
+ And I should see "Question 1" in the ".info" "css_element"
+ And I should see "Not complete" in the ".info" "css_element"
+ And I should see "Marked out of 2.00" in the ".info" "css_element"
+ And I set the field "True" to "1"
+ And I press "Finish attempt ..."
+ And I press "Submit all and finish"
+ And I click on "Submit all and finish" "button" in the "Submit all your answers and finish?" "dialogue"
+ Then I should see "Finished" in the "State" "table_row"
+ And I should see "Question 1" in the ".info" "css_element"
+ And I should see "Correct" in the ".info" "css_element"
+ And I should see "Mark 2.00 out of 2.00" in the ".info" "css_element"
+
+ And I am on the "Quiz 2" "quiz activity" page
+ And I click on "Attempt quiz" "button"
+ And I should see "Question 1" in the ".info" "css_element"
+ And I should see "Not complete" in the ".info" "css_element"
+ And I should not see "Marked out of 2.00" in the ".info" "css_element"
+ And I set the field "True" to "1"
+ And I press "Finish attempt ..."
+ And I press "Submit all and finish"
+ And I click on "Submit all and finish" "button" in the "Submit all your answers and finish?" "dialogue"
+ And I should see "Finished" in the "State" "table_row"
+ And I should see "Question 1" in the ".info" "css_element"
+ And I should see "Correct" in the ".info" "css_element"
+ And I should see "Mark 2.00 out of 2.00" in the ".info" "css_element"
diff --git a/mod/quiz/tests/behat/settings_form_fields_disableif.feature b/mod/quiz/tests/behat/settings_form_fields_disableif.feature
index 56bdfe89c3c..8062d3e0e56 100644
--- a/mod/quiz/tests/behat/settings_form_fields_disableif.feature
+++ b/mod/quiz/tests/behat/settings_form_fields_disableif.feature
@@ -102,6 +102,7 @@ Feature: Settings form fields disabled if not required
And I set the field "Name" to "Test quiz"
Then the "id_attemptclosed" "checkbox" should be disabled
And the "id_correctnessclosed" "checkbox" should be disabled
+ And the "id_maxmarksclosed" "checkbox" should be disabled
And the "id_marksclosed" "checkbox" should be disabled
And the "id_specificfeedbackclosed" "checkbox" should be disabled
And the "id_generalfeedbackclosed" "checkbox" should be disabled
@@ -110,11 +111,16 @@ Feature: Settings form fields disabled if not required
And I set the field "id_timeclose_enabled" to "1"
And the "id_attemptclosed" "checkbox" should be enabled
And the "id_correctnessclosed" "checkbox" should be enabled
+ And the "id_maxmarksclosed" "checkbox" should be enabled
And the "id_marksclosed" "checkbox" should be enabled
+ And I set the field "id_maxmarksclosed" to "0"
+ And the "id_marksclosed" "checkbox" should be disabled
And the "id_specificfeedbackclosed" "checkbox" should be enabled
And the "id_generalfeedbackclosed" "checkbox" should be enabled
And the "id_rightanswerclosed" "checkbox" should be enabled
And the "id_overallfeedbackclosed" "checkbox" should be enabled
+ And I set the field "id_maxmarksduring" to "0"
+ And the "id_marksduring" "checkbox" should be disabled
And I should not see "Repaginate now"
@javascript
diff --git a/mod/quiz/tests/custom_completion_test.php b/mod/quiz/tests/custom_completion_test.php
index e1c61c2da00..5d8084d0066 100644
--- a/mod/quiz/tests/custom_completion_test.php
+++ b/mod/quiz/tests/custom_completion_test.php
@@ -485,6 +485,7 @@ class custom_completion_test extends advanced_testcase {
$moduleinfo->modulename = 'quiz';
$moduleinfo->quizpassword = '';
$moduleinfo->cmidnumber = '';
+ $moduleinfo->maxmarksopen = 1;
$moduleinfo->marksopen = 1;
$moduleinfo->visible = 1;
$moduleinfo->visibleoncoursepage = 1;
diff --git a/mod/quiz/tests/external/external_test.php b/mod/quiz/tests/external/external_test.php
index 9c8cf01de62..9fc37410f38 100644
--- a/mod/quiz/tests/external/external_test.php
+++ b/mod/quiz/tests/external/external_test.php
@@ -246,7 +246,7 @@ class external_test extends externallib_advanced_testcase {
'timeopen', 'timeclose', 'grademethod', 'section', 'visible', 'groupmode', 'groupingid',
'attempts', 'timelimit', 'grademethod', 'decimalpoints', 'questiondecimalpoints', 'sumgrades',
'grade', 'preferredbehaviour', 'hasfeedback'];
- $userswithaccessfields = ['attemptonlast', 'reviewattempt', 'reviewcorrectness', 'reviewmarks',
+ $userswithaccessfields = ['attemptonlast', 'reviewattempt', 'reviewcorrectness', 'reviewmaxmarks', 'reviewmarks',
'reviewspecificfeedback', 'reviewgeneralfeedback', 'reviewrightanswer',
'reviewoverallfeedback', 'questionsperpage', 'navmethod',
'browsersecurity', 'delay1', 'delay2', 'showuserpicture', 'showblocks',
diff --git a/mod/quiz/tests/generator/lib.php b/mod/quiz/tests/generator/lib.php
index 9e175f958cf..b5e50634dc5 100644
--- a/mod/quiz/tests/generator/lib.php
+++ b/mod/quiz/tests/generator/lib.php
@@ -45,6 +45,7 @@ class mod_quiz_generator extends testing_module_generator {
'questiondecimalpoints' => -1,
'attemptduring' => 1,
'correctnessduring' => 1,
+ 'maxmarksduring' => 1,
'marksduring' => 1,
'specificfeedbackduring' => 1,
'generalfeedbackduring' => 1,
@@ -52,6 +53,7 @@ class mod_quiz_generator extends testing_module_generator {
'overallfeedbackduring' => 0,
'attemptimmediately' => 1,
'correctnessimmediately' => 1,
+ 'maxmarksimmediately' => 1,
'marksimmediately' => 1,
'specificfeedbackimmediately' => 1,
'generalfeedbackimmediately' => 1,
@@ -59,6 +61,7 @@ class mod_quiz_generator extends testing_module_generator {
'overallfeedbackimmediately' => 1,
'attemptopen' => 1,
'correctnessopen' => 1,
+ 'maxmarksopen' => 1,
'marksopen' => 1,
'specificfeedbackopen' => 1,
'generalfeedbackopen' => 1,
@@ -66,6 +69,7 @@ class mod_quiz_generator extends testing_module_generator {
'overallfeedbackopen' => 1,
'attemptclosed' => 1,
'correctnessclosed' => 1,
+ 'maxmarksclosed' => 1,
'marksclosed' => 1,
'specificfeedbackclosed' => 1,
'generalfeedbackclosed' => 1,
diff --git a/mod/quiz/tests/question/display_options_test.php b/mod/quiz/tests/question/display_options_test.php
index 135cbb80a63..21e245c8f06 100644
--- a/mod/quiz/tests/question/display_options_test.php
+++ b/mod/quiz/tests/question/display_options_test.php
@@ -37,7 +37,8 @@ class display_options_test extends \basic_testcase {
$quiz->questiondecimalpoints = -1;
$quiz->reviewattempt = 0x11110;
$quiz->reviewcorrectness = 0x10000;
- $quiz->reviewmarks = 0x01110;
+ $quiz->reviewmaxmarks = 0x10000; // Max marks is set.
+ $quiz->reviewmarks = 0x00000; // Marks is not set.
$quiz->reviewspecificfeedback = 0x10000;
$quiz->reviewgeneralfeedback = 0x01000;
$quiz->reviewrightanswer = 0x00100;
@@ -56,6 +57,8 @@ class display_options_test extends \basic_testcase {
$this->assertEquals(2, $options->markdp);
$quiz->questiondecimalpoints = 5;
+ $quiz->reviewmaxmarks = 0x11000; // Max marks is set.
+ $quiz->reviewmarks = 0x11000; // Marks is also set.
$options = display_options::make_from_quiz($quiz,
display_options::IMMEDIATELY_AFTER);
@@ -67,9 +70,12 @@ class display_options_test extends \basic_testcase {
$this->assertEquals(display_options::HIDDEN, $options->manualcomment);
$this->assertEquals(5, $options->markdp);
+ $quiz->reviewmaxmarks = 0x00000; // Max marks is NOT set.
+ $quiz->reviewmarks = 0x00000; // Marks is also NOT set.
$options = display_options::make_from_quiz($quiz,
display_options::LATER_WHILE_OPEN);
+ $this->assertEquals(display_options::HIDDEN, $options->marks);
$this->assertEquals(display_options::VISIBLE, $options->rightanswer);
$this->assertEquals(display_options::HIDDEN, $options->generalfeedback);
diff --git a/mod/quiz/version.php b/mod/quiz/version.php
index 68935482667..8b24296204a 100644
--- a/mod/quiz/version.php
+++ b/mod/quiz/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2023042400;
+$plugin->version = 2023042401;
$plugin->requires = 2023041800;
$plugin->component = 'mod_quiz';