MDL-37998 quiz settings: disableif rules should account for overrides.
authorTim Hunt <T.J.Hunt@open.ac.uk>
Sun, 14 Sep 2014 13:14:11 +0000 (14:14 +0100)
committerDan Poltawski <dan@moodle.com>
Mon, 22 Sep 2014 15:23:38 +0000 (16:23 +0100)
Some form fields are disabled if only one attempt is allowed. However,
there may be an override allowing some students more attempts. We need
to account for that possiblity when setting up the disabled if rules.

Note the disabledIf is good for usability on this complex form, which is
why I don't just want to get rid of them.

mod/quiz/mod_form.php
mod/quiz/tests/behat/settings_form_fields_disableif.feature [new file with mode: 0644]

index 912bcae..6c8c1f5 100644 (file)
@@ -42,6 +42,9 @@ class mod_quiz_mod_form extends moodleform_mod {
     protected $_feedbacks;
     protected static $reviewfields = array(); // Initialised in the constructor.
 
+    /** @var int the max number of attempts allowed in any user or group override on this quiz. */
+    protected $maxattemptsanyoverride = null;
+
     public function __construct($current, $section, $cm, $course) {
         self::$reviewfields = array(
             'attempt'          => array('theattempt', 'quiz'),
@@ -136,7 +139,9 @@ class mod_quiz_mod_form extends moodleform_mod {
         $mform->addHelpButton('grademethod', 'grademethod', 'quiz');
         $mform->setAdvanced('grademethod', $quizconfig->grademethod_adv);
         $mform->setDefault('grademethod', $quizconfig->grademethod);
-        $mform->disabledIf('grademethod', 'attempts', 'eq', 1);
+        if ($this->get_max_attempts_for_any_override() < 2) {
+            $mform->disabledIf('grademethod', 'attempts', 'eq', 1);
+        }
 
         // -------------------------------------------------------------------------------
         $mform->addElement('header', 'layouthdr', get_string('layout', 'quiz'));
@@ -219,7 +224,9 @@ class mod_quiz_mod_form extends moodleform_mod {
         $mform->addHelpButton('attemptonlast', 'eachattemptbuildsonthelast', 'quiz');
         $mform->setAdvanced('attemptonlast', $quizconfig->attemptonlast_adv);
         $mform->setDefault('attemptonlast', $quizconfig->attemptonlast);
-        $mform->disabledIf('attemptonlast', 'attempts', 'eq', 1);
+        if ($this->get_max_attempts_for_any_override() < 2) {
+            $mform->disabledIf('attemptonlast', 'attempts', 'eq', 1);
+        }
 
         // -------------------------------------------------------------------------------
         $mform->addElement('header', 'reviewoptionshdr',
@@ -309,15 +316,19 @@ class mod_quiz_mod_form extends moodleform_mod {
         $mform->addHelpButton('delay1', 'delay1st2nd', 'quiz');
         $mform->setAdvanced('delay1', $quizconfig->delay1_adv);
         $mform->setDefault('delay1', $quizconfig->delay1);
-        $mform->disabledIf('delay1', 'attempts', 'eq', 1);
+        if ($this->get_max_attempts_for_any_override() < 2) {
+            $mform->disabledIf('delay1', 'attempts', 'eq', 1);
+        }
 
         $mform->addElement('duration', 'delay2', get_string('delaylater', 'quiz'),
                 array('optional' => true));
         $mform->addHelpButton('delay2', 'delaylater', 'quiz');
         $mform->setAdvanced('delay2', $quizconfig->delay2_adv);
         $mform->setDefault('delay2', $quizconfig->delay2);
-        $mform->disabledIf('delay2', 'attempts', 'eq', 1);
-        $mform->disabledIf('delay2', 'attempts', 'eq', 2);
+        if ($this->get_max_attempts_for_any_override() < 3) {
+            $mform->disabledIf('delay2', 'attempts', 'eq', 1);
+            $mform->disabledIf('delay2', 'attempts', 'eq', 2);
+        }
 
         // Browser security choices.
         $mform->addElement('select', 'browsersecurity', get_string('browsersecurity', 'quiz'),
@@ -618,4 +629,33 @@ class mod_quiz_mod_form extends moodleform_mod {
     public function completion_rule_enabled($data) {
         return !empty($data['completionattemptsexhausted']) || !empty($data['completionpass']);
     }
+
+    /**
+     * Get the maximum number of attempts that anyone might have due to a user
+     * or group override. Used to decide whether disabledIf rules should be applied.
+     * @return int the number of attempts allowed. For the purpose of this method,
+     * unlimited is returned as 1000, not 0.
+     */
+    public function get_max_attempts_for_any_override() {
+        global $DB;
+
+        if (empty($this->_instance)) {
+            // Quiz not created yet, so no overrides.
+            return 1;
+        }
+
+        if ($this->maxattemptsanyoverride === null) {
+            $this->maxattemptsanyoverride = $DB->get_field_sql("
+                    SELECT MAX(CASE WHEN attempts = 0 THEN 1000 ELSE attempts END)
+                      FROM {quiz_overrides}
+                     WHERE quiz = ?",
+                    array($this->_instance));
+            if ($this->maxattemptsanyoverride < 1) {
+                // This happens when no override alters the number of attempts.
+                $this->maxattemptsanyoverride = 1;
+            }
+        }
+
+        return $this->maxattemptsanyoverride;
+    }
 }
diff --git a/mod/quiz/tests/behat/settings_form_fields_disableif.feature b/mod/quiz/tests/behat/settings_form_fields_disableif.feature
new file mode 100644 (file)
index 0000000..0e7213e
--- /dev/null
@@ -0,0 +1,92 @@
+@mod @mod_quiz
+Feature: Settings form fields disabled if not required
+  In to create quizzes as simply as possible
+  As a teacher
+  I don't need to to use certain form fields.
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname |
+      | teacher  | Teach     |
+      | student1 | Student1  |
+      | student2 | Student2  |
+    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        |
+      | student2 | C1     | student        |
+    And I log in as "teacher"
+    And I follow "Course 1"
+    And I turn editing mode on
+
+  @javascript
+  Scenario: Depending on the number of attempts, different form fields are disabled.
+    When I add a "Quiz" to section "1"
+    And I expand all fieldsets
+    And I set the field "Name" to "Test quiz"
+    And I set the field "Attempts allowed" to "1"
+    Then the "Grading method" "field" should be disabled
+    And the "Each attempt builds on the last" "field" should be disabled
+    And the "id_delay1_enabled" "field" should be disabled
+    And the "id_delay2_enabled" "field" should be disabled
+
+    When I set the field "Attempts allowed" to "2"
+    Then the "Grading method" "field" should be enabled
+    And the "Each attempt builds on the last" "field" should be enabled
+    And the "id_delay1_enabled" "field" should be enabled
+    And the "id_delay2_enabled" "field" should be disabled
+
+    When I set the field "Attempts allowed" to "3"
+    Then the "Grading method" "field" should be enabled
+    And the "Each attempt builds on the last" "field" should be enabled
+    And the "id_delay1_enabled" "field" should be enabled
+    And the "id_delay2_enabled" "field" should be enabled
+
+    When I set the field "Attempts allowed" to "Unlimited"
+    Then the "Grading method" "field" should be enabled
+    And the "Each attempt builds on the last" "field" should be enabled
+    # And the "id_delay1_enabled" "field" should be enabled
+    # And the "id_delay2_enabled" "field" should be enabled
+
+    When I press "Save and display"
+    And I navigate to "User overrides" node in "Quiz administration"
+    And I press "Add user override"
+    And I set the following fields to these values:
+        | Override user    | Student1 |
+        | Attempts allowed | 3        |
+    And I press "Save"
+    And I navigate to "Edit settings" node in "Quiz administration"
+    And I set the field "Attempts allowed" to "1"
+    Then the "Grading method" "field" should be enabled
+    And the "Each attempt builds on the last" "field" should be enabled
+    And the "id_delay1_enabled" "field" should be enabled
+    And the "id_delay2_enabled" "field" should be enabled
+
+    When I press "Save and display"
+    And I navigate to "User overrides" node in "Quiz administration"
+    And I follow "Edit"
+    And I set the field "Attempts allowed" to "2"
+    And I press "Save"
+    And I navigate to "Edit settings" node in "Quiz administration"
+    And I set the field "Attempts allowed" to "1"
+    Then the "Grading method" "field" should be enabled
+    And the "Each attempt builds on the last" "field" should be enabled
+    And the "id_delay1_enabled" "field" should be enabled
+    And the "id_delay2_enabled" "field" should be disabled
+
+    When I press "Save and display"
+    And I navigate to "User overrides" node in "Quiz administration"
+    And I press "Add user override"
+    And I set the following fields to these values:
+        | Override user    | Student2  |
+        | Attempts allowed | Unlimited |
+    And I press "Save"
+    And I navigate to "Edit settings" node in "Quiz administration"
+    And I set the field "Attempts allowed" to "1"
+    Then the "Grading method" "field" should be enabled
+    And the "Each attempt builds on the last" "field" should be enabled
+    And the "id_delay1_enabled" "field" should be enabled
+    And the "id_delay2_enabled" "field" should be enabled