Merge branch 'MDL-49324-master' of git://github.com/andrewnicols/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Wed, 24 Feb 2016 06:55:51 +0000 (07:55 +0100)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Wed, 24 Feb 2016 06:55:51 +0000 (07:55 +0100)
23 files changed:
grade/edit/tree/index.php
grade/export/lib.php
grade/lib.php
grade/report/grader/index.php
grade/report/outcomes/index.php
grade/report/overview/index.php
grade/report/singleview/index.php
grade/report/singleview/tests/behat/bulk_insert_grades.feature
grade/report/singleview/tests/behat/singleview.feature
grade/report/singleview/tests/screen_test.php
grade/report/user/index.php
grade/report/user/lib.php
grade/report/user/tests/behat/view_usereport.feature
grade/tests/behat/grade_UI_settings.feature
grade/tests/behat/grade_override_letter.feature
grade/tests/behat/grade_point_maximum.feature
grade/tests/behat/grade_scales_aggregation.feature
grade/tests/behat/grade_single_item_scales.feature
grade/tests/behat/grade_to_pass.feature
lang/en/error.php
lang/en/grades.php
lib/classes/progress/display.php
lib/gradelib.php

index 672888a..49ab967 100644 (file)
@@ -30,8 +30,7 @@ require_once $CFG->dirroot.'/grade/edit/tree/lib.php';
 $courseid        = required_param('id', PARAM_INT);
 $action          = optional_param('action', 0, PARAM_ALPHA);
 $eid             = optional_param('eid', 0, PARAM_ALPHANUM);
-$category        = optional_param('category', null, PARAM_INT);
-$aggregationtype = optional_param('aggregationtype', null, PARAM_INT);
+$weightsadjusted = optional_param('weightsadjusted', 0, PARAM_INT);
 
 $url = new moodle_url('/grade/edit/tree/index.php', array('id' => $courseid));
 $PAGE->set_url($url);
@@ -53,33 +52,6 @@ $PAGE->requires->js('/grade/edit/tree/functions.js');
 $gpr = new grade_plugin_return(array('type'=>'edit', 'plugin'=>'tree', 'courseid'=>$courseid));
 $returnurl = $gpr->get_return_url(null);
 
-// Change category aggregation if requested
-if (!is_null($category) && !is_null($aggregationtype) && confirm_sesskey()) {
-    if (!$grade_category = grade_category::fetch(array('id'=>$category, 'courseid'=>$courseid))) {
-        print_error('invalidcategoryid');
-    }
-
-    $data = new stdClass();
-    $data->aggregation = $aggregationtype;
-    grade_category::set_properties($grade_category, $data);
-    $grade_category->update();
-
-    grade_regrade_final_grades($courseid);
-}
-
-//first make sure we have proper final grades - we need it for locking changes
-$normalisationmessage = null;
-
-$originalweights = grade_helper::fetch_all_natural_weights_for_course($courseid);
-
-grade_regrade_final_grades($courseid);
-
-$alteredweights = grade_helper::fetch_all_natural_weights_for_course($courseid);
-
-if (array_diff($originalweights, $alteredweights)) {
-    $normalisationmessage = get_string('weightsadjusted', 'grades');
-}
-
 // get the grading tree object
 // note: total must be first for moving to work correctly, if you want it last moving code must be rewritten!
 $gtree = new grade_tree($courseid, false, false);
@@ -233,15 +205,32 @@ if ($data = data_submitted() and confirm_sesskey()) {
             $recreatetree = true;
         }
     }
+}
 
-    $originalweights = grade_helper::fetch_all_natural_weights_for_course($courseid);
+$originalweights = grade_helper::fetch_all_natural_weights_for_course($courseid);
 
-    grade_regrade_final_grades($courseid);
+/**
+ * Callback function to adjust the URL if weights changed after the
+ * regrade.
+ *
+ * @param int $courseid The course ID
+ * @param array $originalweights The weights before the regrade
+ * @param int $weightsadjusted Whether weights have been adjusted
+ * @return moodle_url A URL to redirect to after regrading when a progress bar is displayed.
+ */
+$grade_edit_tree_index_checkweights = function() use ($courseid, $originalweights, &$weightsadjusted) {
+    global $PAGE;
 
     $alteredweights = grade_helper::fetch_all_natural_weights_for_course($courseid);
     if (array_diff($originalweights, $alteredweights)) {
-        $normalisationmessage = get_string('weightsadjusted', 'grades');
+        $weightsadjusted = 1;
+        return new moodle_url($PAGE->url, array('weightsadjusted' => $weightsadjusted));
     }
+    return $PAGE->url;
+};
+
+if (grade_regrade_final_grades_if_required($course, $grade_edit_tree_index_checkweights)) {
+    $recreatetree = true;
 }
 
 print_grade_page_head($courseid, 'settings', 'setup', get_string('gradebooksetup', 'grades'));
@@ -257,9 +246,10 @@ echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
 if ($recreatetree) {
     $grade_edit_tree = new grade_edit_tree($gtree, $movingeid, $gpr);
 }
+
 // Check to see if we have a normalisation message to send.
-if (!empty($normalisationmessage)) {
-    echo $OUTPUT->notification($normalisationmessage, 'notifymessage');
+if ($weightsadjusted) {
+    echo $OUTPUT->notification(get_string('weightsadjusted', 'grades'), 'notifymessage');
 }
 
 echo html_writer::table($grade_edit_tree->table);
index bf7b981..755fa8a 100644 (file)
@@ -699,8 +699,7 @@ class grade_export_update_buffer {
  * @param $courseid int The course being exported
  */
 function export_verify_grades($courseid) {
-    $regraderesult = grade_regrade_final_grades($courseid);
-    if (is_array($regraderesult)) {
-        throw new moodle_exception('gradecantregrade', 'error', '', implode(', ', array_unique($regraderesult)));
+    if (grade_needs_regrade_final_grades($courseid)) {
+        throw new moodle_exception('gradesneedregrading', 'grades');
     }
 }
index 52c296d..66cf003 100644 (file)
@@ -1002,6 +1002,11 @@ function print_grade_page_head($courseid, $active_type, $active_plugin=null,
         grade_extend_settings($plugin_info, $courseid);
     }
 
+    // Set the current report as active in the breadcrumbs.
+    if ($active_plugin !== null && $reportnav = $PAGE->settingsnav->find($active_plugin, navigation_node::TYPE_SETTING)) {
+        $reportnav->make_active();
+    }
+
     $returnval = $OUTPUT->header();
 
     if (!$return) {
index f15efe2..7885fdc 100644 (file)
@@ -115,9 +115,6 @@ if (!is_null($toggle) && !empty($toggle_type)) {
     set_user_preferences(array('grade_report_show'.$toggle_type => $toggle));
 }
 
-//first make sure we have proper final grades - this must be done before constructing of the grade tree
-grade_regrade_final_grades($courseid);
-
 // Perform actions
 if (!empty($target) && !empty($action) && confirm_sesskey()) {
     grade_report_grader::do_process_action($target, $action, $courseid);
@@ -125,6 +122,9 @@ if (!empty($target) && !empty($action) && confirm_sesskey()) {
 
 $reportname = get_string('pluginname', 'gradereport_grader');
 
+// Do this check just before printing the grade header (and only do it once).
+grade_regrade_final_grades_if_required($course);
+
 // Print header
 print_grade_page_head($COURSE->id, 'report', 'grader', $reportname, false, $buttons);
 
index cc809ab..092373a 100644 (file)
@@ -40,7 +40,7 @@ $context = context_course::instance($course->id);
 require_capability('gradereport/outcomes:view', $context);
 
 // First make sure we have proper final grades.
-grade_regrade_final_grades($courseid);
+grade_regrade_final_grades_if_required($course);
 
 // Grab all outcomes used in course.
 $report_info = array();
index e46885c..14eef55 100644 (file)
@@ -107,8 +107,8 @@ if (!isset($USER->grade_last_report)) {
 }
 $USER->grade_last_report[$course->id] = 'overview';
 
-//first make sure we have proper final grades - this must be done before constructing of the grade tree
-grade_regrade_final_grades($courseid);
+// First make sure we have proper final grades.
+grade_regrade_final_grades_if_required($course);
 
 if (has_capability('moodle/grade:viewall', $context) && $courseid != SITEID) {
     // Please note this would be extremely slow if we wanted to implement this properly for all teachers.
index be9461b..9d6ab82 100644 (file)
@@ -46,7 +46,16 @@ if (empty($itemid)) {
 }
 
 $courseparams = array('id' => $courseid);
-$PAGE->set_url(new moodle_url('/grade/report/singleview/index.php', $courseparams));
+$pageparams = array(
+        'id'        => $courseid,
+        'group'     => $groupid,
+        'userid'    => $userid,
+        'itemid'    => $itemid,
+        'item'      => $itemtype,
+        'page'      => $page,
+        'perpage'   => $perpage,
+    );
+$PAGE->set_url(new moodle_url('/grade/report/singleview/index.php', $pageparams));
 $PAGE->set_pagelayout('incourse');
 
 if (!$course = $DB->get_record('course', $courseparams)) {
@@ -78,9 +87,8 @@ if (!isset($USER->grade_last_report)) {
 }
 $USER->grade_last_report[$course->id] = 'singleview';
 
-// First make sure we have proper final grades -
-// this must be done before constructing of the grade tree.
-grade_regrade_final_grades($courseid);
+// First make sure we have proper final grades.
+grade_regrade_final_grades_if_required($course);
 
 $report = new gradereport_singleview($courseid, $gpr, $context, $itemtype, $itemid);
 
index a06a182..218a832 100644 (file)
@@ -29,7 +29,6 @@ Feature: We can bulk insert grades for students in a course
       | assign | C1 | a3 | Test assignment three | Submit something! |
       | assign | C1 | a4 | Test assignment four | Submit nothing!    |
 
-  @javascript
   Scenario: I can bulk insert grades and check their override flags for grade view.
     Given I log in as "teacher1"
     And I follow "Course 1"
@@ -44,7 +43,7 @@ Feature: We can bulk insert grades for students in a course
     And I follow "Single view for Test assignment one"
     Then the field "Grade for james (Student) 1" matches value "50.00"
     And the field "Override for james (Student) 1" matches value "0"
-    And I click on "Perform bulk insert" "checkbox"
+    And I set the field "Perform bulk insert" to "1"
     And I set the field "Insert value" to "1.0"
     And I press "Save"
     And I press "Continue"
@@ -56,8 +55,8 @@ Feature: We can bulk insert grades for students in a course
     And the field "Override for anna (Student) 3" matches value "1"
     And the field "Grade for zac (Student) 4" matches value "1.00"
     And the field "Override for zac (Student) 4" matches value "1"
-    And I click on "All grades" "option"
-    And I click on "Perform bulk insert" "checkbox"
+    And I set the field "For" to "All grades"
+    And I set the field "Perform bulk insert" to "1"
     And I set the field "Insert value" to "2.0"
     And I press "Save"
     And I press "Continue"
@@ -70,7 +69,6 @@ Feature: We can bulk insert grades for students in a course
     And the field "Grade for zac (Student) 4" matches value "2.00"
     And the field "Override for zac (Student) 4" matches value "1"
 
-  @javascript
   Scenario: I can bulk insert grades and check their override flags for user view.
     Given I log in as "teacher1"
     And I follow "Course 1"
@@ -83,11 +81,11 @@ Feature: We can bulk insert grades for students in a course
     And I press "Continue"
     And I follow "View gradebook"
     And I follow "Single view for Test assignment two"
-    And I click on "Student 1" "option"
+    And I select "Student 1" from the "Select user..." singleselect
     Then the field "Grade for Test assignment two" matches value "50.00"
     And the field "Override for Test assignment two" matches value "0"
-    And I click on "Perform bulk insert" "checkbox"
-    And I click on "Empty grades" "option"
+    And I set the field "For" to "Empty grades"
+    And I set the field "Perform bulk insert" to "1"
     And I set the field "Insert value" to "1.0"
     And I press "Save"
     And I press "Continue"
index 8036568..f12404d 100644 (file)
@@ -50,13 +50,13 @@ Feature: We can use Single view
 
   @javascript
   Scenario: I can update grades, add feedback and exclude grades.
-    Given I click on "Single view" "option"
-    And I click on "Student 4" "option"
-    And I click on "Override for Test assignment one" "checkbox"
+    Given I select "Single view" from the "Grade report" singleselect
+    And I select "Student 4" from the "Select user..." singleselect
+    And I set the field "Override for Test assignment one" to "1"
     When I set the following fields to these values:
         | Grade for Test assignment one | 10.00 |
         | Feedback for Test assignment one | test data |
-    And I click on "Exclude for Test assignment four" "checkbox"
+    And I set the field "Exclude for Test assignment four" to "1"
     And I press "Save"
     Then I should see "Grades were set for 2 items"
     And I press "Continue"
@@ -74,14 +74,13 @@ Feature: We can use Single view
     And I set the following fields to these values:
         | Grade for james (Student) 1 | 12.05 |
         | Feedback for james (Student) 1 | test data2 |
-    And I click on "Exclude for holly (Student) 2" "checkbox"
+    And I set the field "Exclude for holly (Student) 2" to "1"
     And I press "Save"
     Then I should see "Grades were set for 2 items"
     And I press "Continue"
     And the field "Grade for james (Student) 1" matches value "12.05"
     And the field "Exclude for holly (Student) 2" matches value "1"
-    And I click on "Single view" "link"
-    And I click on "new grade item 1" "option"
+    And I select "new grade item 1" from the "Select grade item..." singleselect
     And I click on "Very good" "option"
     And I press "Save"
     Then I should see "Grades were set for 1 items"
@@ -97,13 +96,12 @@ Feature: We can use Single view
     And I follow "Single view for Student 1"
     Then I should see "Student 1"
 
-  @javascript
   Scenario: I can bulk update grades.
     Given I follow "Single view for Student 1"
     Then I should see "Student 1"
-    When I click on "All grades" "option"
+    When I set the field "For" to "All grades"
     And I set the field "Insert value" to "1.0"
-    And I click on "Perform bulk insert" "checkbox"
+    And I set the field "Perform bulk insert" to "1"
     And I press "Save"
     Then I should see "Grades were set for 8 items"
 
index 2476d08..eed9921 100644 (file)
@@ -23,8 +23,9 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-
+global $CFG;
 require_once(__DIR__ . '/fixtures/screen.php');
+require_once($CFG->libdir . '/gradelib.php');
 
 defined('MOODLE_INTERNAL') || die();
 /**
@@ -59,6 +60,8 @@ class gradereport_singleview_screen_testcase extends advanced_testcase {
         $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user1->id));
         $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user2->id));
 
+        // Perform a regrade before creating the report.
+        grade_regrade_final_grades($course->id);
         $screentest = new gradereport_singleview_screen_testable($course->id, 0, $group->id);
         $groupusers = $screentest->test_load_users();
         $this->assertCount(2, $groupusers);
@@ -89,4 +92,4 @@ class gradereport_singleview_screen_testcase extends advanced_testcase {
         $users = $screentest->test_load_users();
         $this->assertCount(2, $users);
     }
-}
\ No newline at end of file
+}
index 149879c..1e8460e 100644 (file)
@@ -79,9 +79,8 @@ if (!isset($USER->grade_last_report)) {
 }
 $USER->grade_last_report[$course->id] = 'user';
 
-
-//first make sure we have proper final grades - this must be done before constructing of the grade tree
-grade_regrade_final_grades($courseid);
+// First make sure we have proper final grades.
+grade_regrade_final_grades_if_required($course);
 
 if (has_capability('moodle/grade:viewall', $context)) { //Teachers will see all student reports
     $groupmode    = groups_get_course_groupmode($course);   // Groups are being used
index 0f35f82..65f66a6 100644 (file)
@@ -1163,9 +1163,6 @@ function grade_report_user_profilereport($course, $user, $viewasuser = false) {
 
         $context = context_course::instance($course->id);
 
-        //first make sure we have proper final grades - this must be done before constructing of the grade tree
-        grade_regrade_final_grades($course->id);
-
         /// return tracking object
         $gpr = new grade_plugin_return(array('type'=>'report', 'plugin'=>'user', 'courseid'=>$course->id, 'userid'=>$user->id));
         // Create a report instance
index b4051b8..9bc1f8f 100644 (file)
@@ -14,7 +14,5 @@ Feature: We can use the user report
       And I follow "Course 1"
       And I navigate to "Grades" node in "Course administration"
       And I select "User report" from the "Grade report" singleselect
-      And I press "Go"
       And I select "All users (0)" from the "Select all or one user" singleselect
-      And I click on "Go" "button" in the "#choosegradeuser" "css_element"
       Then I should see "No students enrolled in this course yet"
index 72b1feb..e01b928 100644 (file)
@@ -28,7 +28,7 @@ Feature: Site settings can be used to hide parts of the gradebook UI
     When I click on "Edit  assign Assignment1" "link"
     And I should see "Minimum grade"
     Then I navigate to "General settings" node in "Site administration > Grades"
-    And I click on "Show minimum grade" "checkbox"
+    And I set the field "Show minimum grade" to "0"
     And I press "Save changes"
     And I am on site homepage
     And I follow "Course 1"
@@ -40,7 +40,7 @@ Feature: Site settings can be used to hide parts of the gradebook UI
   Scenario: Hide calculation icons
     And "Edit calculation for   Course total" "link" should exist
     When I navigate to "Grader report" node in "Site administration > Grades > Report settings"
-    And I click on "Show calculations" "checkbox"
+    And I set the field "Show calculations" to "0"
     And I press "Save changes"
     And I am on site homepage
     And I follow "Course 1"
@@ -51,7 +51,7 @@ Feature: Site settings can be used to hide parts of the gradebook UI
   Scenario: Disable category overriding
     And "tr .course input[type='text']" "css_element" should exist
     Then I navigate to "Grade category settings" node in "Site administration > Grades"
-    And I click on "Allow category grades to be manually overridden" "checkbox"
+    And I set the field "Allow category grades to be manually overridden" to "0"
     And I press "Save changes"
     And I am on site homepage
     And I follow "Course 1"
index 12ac7d3..6abdcb9 100644 (file)
@@ -204,4 +204,4 @@ Feature: Grade letters can be overridden
       | 89.99 %  | 85.00 %  | β      |
       | 84.99 %  | 70.00 %  | γ      |
       | 69.99 %  | 55.00 %  | δ      |
-      | 54.99 %  | 0.00 %   | Ω      |
\ No newline at end of file
+      | 54.99 %  | 0.00 %   | Ω      |
index 1070302..c750f81 100644 (file)
@@ -76,7 +76,6 @@ Feature: We can change the grading type and maximum grade point values
     And the "Maximum grade" "field" should be disabled
     And I press "Save and return to course"
 
-  @javascript
   Scenario: Create an activity with a maximum grade point value higher than the system maximum
     When I follow "Test Assignment 1"
     And I follow "Edit settings"
@@ -87,7 +86,6 @@ Feature: We can change the grading type and maximum grade point values
     Then I should see "Invalid grade value. This must be an integer between 1 and 900"
     And I press "Cancel"
 
-  @javascript
   Scenario: Create an activity with a valid maximum grade point and then change the system maximum to be lower
     When I follow "Test Assignment 1"
     And I follow "Edit settings"
index 2c74e52..b866294 100644 (file)
@@ -36,7 +36,6 @@ Feature: Control the aggregation of the scales
       | grade_includescalesinaggregation | 0 |
     And I log out
 
-  @javascript
   Scenario Outline: Scales can be excluded from aggregation
     Given I log in as "teacher1"
     And I follow "Course 1"
index 190e1f7..ed3a96a 100644 (file)
@@ -56,7 +56,6 @@ Feature: View gradebook when single item scales are used
     And I follow "Grader report"
     And I turn editing mode on
 
-  @javascript
   Scenario: Test displaying single item scales in gradebook in aggregation method Natural
     When I turn editing mode off
     Then the following should exist in the "user-grades" table:
@@ -67,36 +66,33 @@ Feature: View gradebook when single item scales are used
       | Range              | Ace!–Ace! | 0.00–1.00      | 0.00–1.00    |
       | Overall average    | Ace!      | 1.00           | 1.00         |
     And I follow "User report"
-    And I set the field "Select all or one user" to "Student 1"
+    And I select "Student 1" from the "Select all or one user" singleselect
     And the following should exist in the "user-grade" table:
       | Grade item          | Grade | Range     | Contribution to course total |
       | Test assignment one | Ace!  | Ace!–Ace! | 100.00 %                     |
       | Sub category 1 total| 1.00  | 0–1       | -                            |
       | Course total        | 1.00  | 0–1       | -                            |
-    And I set the field "Select all or one user" to "Student 2"
+    And I select "Student 2" from the "Select all or one user" singleselect
     And the following should exist in the "user-grade" table:
       | Grade item          | Grade | Range     | Contribution to course total |
       | Test assignment one | -     | Ace!–Ace! | -                            |
       | Sub category 1 total| -     | 0–1       | -                            |
       | Course total        | -     | 0–1       | -                            |
-    And I set the field "jump" to "Gradebook setup"
+    And I select "Gradebook setup" from the "jump" singleselect
     And the following should exist in the "grade_edit_tree_table" table:
       | Name                | Max grade |
       | Test assignment one | 1.00      |
       | Sub category 1 total| 1.00      |
       | Course total        | 1.00      |
 
-  @javascript
   Scenario Outline: Test displaying single item scales in gradebook in all other aggregation methods
     When I follow "Edit   Course 1"
     And I set the field "Aggregation" to "<aggregation>"
     And I press "Save changes"
     And I follow "Edit   Sub category 1"
-    And I expand all fieldsets
-    And I set the field "Aggregation" to "<aggregation>"
-    And I set the field "Category name" to "Sub category (<aggregation>)"
-    # And I set the field "Maximum grade" to "5"
-    # And I set the field "Minimum grade" to "1"
+    And I set the following fields to these values:
+      | Aggregation     | <aggregation> |
+      | Category name   | Sub category (<aggregation>) |
     And I press "Save changes"
     And I turn editing mode off
     Then the following should exist in the "user-grades" table:
@@ -108,19 +104,18 @@ Feature: View gradebook when single item scales are used
       | Range              | Ace!–Ace! | 0.00–100.0     | 0.00–100.00    |
       | Overall average    | Ace!      | <catavg>       | <overallavg>   |
     And I follow "User report"
-    And I set the field "Select all or one user" to "Student 1"
-    And I click on "Select all or one user" "select"
+    And I select "Student 1" from the "Select all or one user" singleselect
     And the following should exist in the "user-grade" table:
       | Grade item                                       | Grade          | Range       | Contribution to course total |
       | Test assignment one                              | Ace!           | Ace!–Ace!   | <contrib1>                   |
       | Sub category (<aggregation>) total<aggregation>. | <cattotal1>    | 0–100       | -                            |
       | Course total<aggregation>.                       | <coursetotal1> | 0–100       | -                            |
-    And I set the field "jump" to "Gradebook setup"
+    And I select "Gradebook setup" from the "jump" singleselect
     And the following should exist in the "grade_edit_tree_table" table:
-      | Name                         | Max grade |
-      | Test assignment one          | Ace! (1)  |
+      | Name                                             | Max grade |
+      | Test assignment one                              | Ace! (1)  |
       | Sub category (<aggregation>) total<aggregation>. | 100.00    |
-      | Course total<aggregation>.   | 100.00    |
+      | Course total<aggregation>.                       | 100.00    |
 
     Examples:
       | aggregation                         | contrib1 | cattotal1 | coursetotal1 | catavg | overallavg |
index 34360b1..7125b62 100644 (file)
@@ -45,7 +45,6 @@ Feature: We can set the grade to pass value
     Then I should see "The grade to pass can not be greater than the maximum possible grade 50"
     And I press "Cancel"
 
-  @javascript
   Scenario: Set a valid grade to pass for an assignment activity using points
     When I turn editing mode on
     And I add a "Assignment" to section "1" and I fill the form with:
@@ -69,7 +68,6 @@ Feature: We can set the grade to pass value
     And I click on "Edit  assign Test Assignment 1" "link"
     And the field "Grade to pass" matches value "30"
 
-  @javascript
   Scenario: Set a valid grade to pass for an assignment activity using scales
     When I turn editing mode on
     And I add a "Assignment" to section "1" and I fill the form with:
@@ -81,7 +79,7 @@ Feature: We can set the grade to pass value
     And I navigate to "Grades" node in "Course administration"
     And I turn editing mode on
     And I click on "Edit  assign Test Assignment 1" "link"
-    And I follow "Show more..."
+    And I expand all fieldsets
     Then the field "Grade to pass" matches value "3"
     And I set the field "Grade to pass" to "4"
     And I press "Save changes"
@@ -90,7 +88,6 @@ Feature: We can set the grade to pass value
     And I follow "Edit settings"
     And the field "Grade to pass" matches value "4"
 
-  @javascript
   Scenario: Set a invalid grade to pass for an assignment activity using scales
     When I turn editing mode on
     And I add a "Assignment" to section "1" and I fill the form with:
@@ -101,7 +98,6 @@ Feature: We can set the grade to pass value
       | Grade to pass | 10 |
     Then I should see "The grade to pass can not be greater than the maximum possible grade 4"
 
-  @javascript
   Scenario: Set a valid grade to pass for workshop activity
     When I turn editing mode on
     And I add a "Workshop" to section "1" and I fill the form with:
@@ -114,12 +110,12 @@ Feature: We can set the grade to pass value
     And I navigate to "Grades" node in "Course administration"
     And I turn editing mode on
     And I click on "Edit  workshop Test Workshop 1 (submission)" "link"
-    And I follow "Show more..."
+    And I expand all fieldsets
     Then the field "Grade to pass" matches value "40"
     And I set the field "Grade to pass" to "45"
     And I press "Save changes"
     And I click on "Edit  workshop Test Workshop 1 (assessment)" "link"
-    And I follow "Show more..."
+    And I expand all fieldsets
     And the field "Grade to pass" matches value "10"
     And I set the field "Grade to pass" to "15"
     And I press "Save changes"
@@ -129,7 +125,6 @@ Feature: We can set the grade to pass value
     And the field "Submission grade to pass" matches value "45"
     And the field "Assessment grade to pass" matches value "15"
 
-  @javascript
   Scenario: Set an invalid grade to pass for workshop activity
     When I turn editing mode on
     And I add a "Workshop" to section "1" and I fill the form with:
@@ -142,7 +137,6 @@ Feature: We can set the grade to pass value
     Then "The grade to pass can not be greater than the maximum possible grade 80" "text" should exist in the "#fitem_id_submissiongradepass .error" "css_element"
     Then "The grade to pass can not be greater than the maximum possible grade 20" "text" should exist in the "#fitem_id_gradinggradepass .error" "css_element"
 
-  @javascript
   Scenario: Set a valid grade to pass for quiz activity
     When I turn editing mode on
     And I add a "Quiz" to section "1" and I fill the form with:
@@ -151,7 +145,7 @@ Feature: We can set the grade to pass value
     And I navigate to "Grades" node in "Course administration"
     And I turn editing mode on
     And I click on "Edit  quiz Test Quiz 1" "link"
-    And I follow "Show more..."
+    And I expand all fieldsets
     Then the field "Grade to pass" matches value "9.5"
     And I set the field "Grade to pass" to "8"
     And I press "Save changes"
@@ -160,7 +154,6 @@ Feature: We can set the grade to pass value
     And I follow "Edit settings"
     And the field "Grade to pass" matches value "8.00"
 
-  @javascript
   Scenario: Set a valid grade to pass for lesson activity
     When I turn editing mode on
     And I add a "Lesson" to section "1" and I fill the form with:
@@ -170,7 +163,7 @@ Feature: We can set the grade to pass value
     And I navigate to "Grades" node in "Course administration"
     And I turn editing mode on
     And I click on "Edit  lesson Test Lesson 1" "link"
-    And I follow "Show more..."
+    And I expand all fieldsets
     Then the field "Grade to pass" matches value "90"
     And I set the field "Grade to pass" to "80"
     And I press "Save changes"
@@ -179,7 +172,6 @@ Feature: We can set the grade to pass value
     And I follow "Edit settings"
     And the field "Grade to pass" matches value "80"
 
-  @javascript
   Scenario: Set a valid grade to pass for database activity
     When I turn editing mode on
     And I add a "Database" to section "1" and I fill the form with:
@@ -190,7 +182,7 @@ Feature: We can set the grade to pass value
     And I navigate to "Grades" node in "Course administration"
     And I turn editing mode on
     And I click on "Edit  data Test Database 1" "link"
-    And I follow "Show more..."
+    And I expand all fieldsets
     Then the field "Grade to pass" matches value "90"
     And I set the field "Grade to pass" to "80"
     And I press "Save changes"
@@ -199,7 +191,6 @@ Feature: We can set the grade to pass value
     And I follow "Edit settings"
     And the field "Grade to pass" matches value "80"
 
-  @javascript
   Scenario: Set an invalid grade to pass for forum activity
     When I turn editing mode on
     And I add a "Forum" to section "1" and I fill the form with:
@@ -210,7 +201,6 @@ Feature: We can set the grade to pass value
       | scale[modgrade_point] | 60 |
     Then I should see "The grade to pass can not be greater than the maximum possible grade 60"
 
-  @javascript
   Scenario: Set a valid grade to pass for forum activity
     When I turn editing mode on
     And I add a "Forum" to section "1" and I fill the form with:
@@ -221,7 +211,7 @@ Feature: We can set the grade to pass value
     And I navigate to "Grades" node in "Course administration"
     And I turn editing mode on
     And I click on "Edit  forum Test Forum 1" "link"
-    And I follow "Show more..."
+    And I expand all fieldsets
     Then the field "Grade to pass" matches value "90"
     And I set the field "Grade to pass" to "80"
     And I press "Save changes"
@@ -230,7 +220,6 @@ Feature: We can set the grade to pass value
     And I follow "Edit settings"
     And the field "Grade to pass" matches value "80"
 
-  @javascript
   Scenario: Set a valid grade to pass for glossary activity
     When I turn editing mode on
     And I add a "Glossary" to section "1" and I fill the form with:
@@ -241,7 +230,7 @@ Feature: We can set the grade to pass value
     And I navigate to "Grades" node in "Course administration"
     And I turn editing mode on
     And I click on "Edit  glossary Test Glossary 1" "link"
-    And I follow "Show more..."
+    And I expand all fieldsets
     Then the field "Grade to pass" matches value "90"
     And I set the field "Grade to pass" to "80"
     And I press "Save changes"
index 32aded3..2dc689f 100644 (file)
@@ -254,6 +254,7 @@ $string['filternotinstalled'] = 'Filter {$a} is not currently installed';
 $string['forumblockingtoomanyposts'] = 'You have exceeded the posting threshold set for this forum';
 $string['generalexceptionmessage'] = 'Exception - {$a}';
 $string['gradepubdisable'] = 'Grade publishing disabled';
+$string['gradesneedregrading'] = 'The course grades need to be recalculated';
 $string['gradecantregrade'] = 'An error occurred during grade calculation: {$a}';
 $string['groupalready'] = 'User already belongs to group {$a}';
 $string['groupexistforcourse'] = 'Group "{$a}" already exists for this course';
index 4089b5e..f37a5fe 100644 (file)
@@ -616,6 +616,7 @@ $string['rawpct'] = 'Raw %';
 $string['real'] = 'Real';
 $string['realletter'] = 'Real (letter)';
 $string['realpercentage'] = 'Real (percentage)';
+$string['recalculatinggrades'] = 'Recalculating grades';
 $string['recovergradesdefault'] = 'Recover grades default';
 $string['recovergradesdefault_help'] = 'By default recover old grades when re-enrolling a user in a course.';
 $string['refreshpreview'] = 'Refresh preview';
index 4e3b46f..b7974bc 100644 (file)
@@ -126,6 +126,11 @@ class display extends base {
                     $this->direction = -$this->direction;
                     $this->currentstate += 2 * $this->direction;
                 }
+                $buffersize = ini_get('output_buffering');
+                if ($buffersize) {
+                    // Force the buffer full.
+                    echo str_pad('', $buffersize);
+                }
             }
 
             // Get progress.
index 6dfa227..c50ecd9 100644 (file)
@@ -325,6 +325,86 @@ function grade_update_outcomes($source, $courseid, $itemtype, $itemmodule, $item
     return false; //grade items not found
 }
 
+/**
+ * Return true if the course needs regrading.
+ *
+ * @param int $courseid The course ID
+ * @return bool true if course grades need updating.
+ */
+function grade_needs_regrade_final_grades($courseid) {
+    $course_item = grade_item::fetch_course_item($courseid);
+    return $course_item->needsupdate;
+}
+
+/**
+ * Return true if the regrade process is likely to be time consuming and
+ * will therefore require the progress bar.
+ *
+ * @param int $courseid The course ID
+ * @return bool Whether the regrade process is likely to be time consuming
+ */
+function grade_needs_regrade_progress_bar($courseid) {
+    global $DB;
+    $grade_items = grade_item::fetch_all(array('courseid' => $courseid));
+
+    list($sql, $params) = $DB->get_in_or_equal(array_keys($grade_items), SQL_PARAMS_NAMED, 'gi');
+    $gradecount = $DB->count_records_select('grade_grades', 'itemid ' . $sql, $params);
+
+    // This figure may seem arbitrary, but after analysis it seems that 100 grade_grades can be calculated in ~= 0.5 seconds.
+    // Any longer than this and we want to show the progress bar.
+    return $gradecount > 100;
+}
+
+/**
+ * Check whether regarding of final grades is required and, if so, perform the regrade.
+ *
+ * If the regrade is expected to be time consuming (see grade_needs_regrade_progress_bar), then this
+ * function will output the progress bar, and redirect to the current PAGE->url after regrading
+ * completes. Otherwise the regrading will happen immediately and the page will be loaded as per
+ * normal.
+ *
+ * A callback may be specified, which is called if regrading has taken place.
+ * The callback may optionally return a URL which will be redirected to when the progress bar is present.
+ *
+ * @param stdClass $course The course to regrade
+ * @param callable $callback A function to call if regrading took place
+ * @return moodle_url The URL to redirect to if redirecting
+ */
+function grade_regrade_final_grades_if_required($course, callable $callback = null) {
+    global $PAGE, $OUTPUT;
+
+    if (!grade_needs_regrade_final_grades($course->id)) {
+        return false;
+    }
+
+    if (grade_needs_regrade_progress_bar($course->id)) {
+        $PAGE->set_heading($course->fullname);
+        echo $OUTPUT->header();
+        echo $OUTPUT->heading(get_string('recalculatinggrades', 'grades'));
+        $progress = new \core\progress\display(true);
+        grade_regrade_final_grades($course->id, null, null, $progress);
+
+        if ($callback) {
+            //
+            $url = call_user_func($callback);
+        }
+
+        if (empty($url)) {
+            $url = $PAGE->url;
+        }
+
+        echo $OUTPUT->continue_button($url);
+        echo $OUTPUT->footer();
+        die();
+    } else {
+        $result = grade_regrade_final_grades($course->id);
+        if ($callback) {
+            call_user_func($callback);
+        }
+        return $result;
+    }
+}
+
 /**
  * Returns grading information for given activity, optionally with user grades
  * Manual, course or category items can not be queried.
@@ -1011,14 +1091,19 @@ function grade_recover_history_grades($userid, $courseid) {
  * @param int $courseid The course ID
  * @param int $userid If specified try to do a quick regrading of the grades of this user only
  * @param object $updated_item Optional grade item to be marked for regrading
+ * @param \core\progress\base $progress If provided, will be used to update progress on this long operation.
  * @return bool true if ok, array of errors if problems found. Grade item id => error message
  */
-function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null) {
+function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null, $progress=null) {
     // This may take a very long time.
     \core_php_time_limit::raise();
 
     $course_item = grade_item::fetch_course_item($courseid);
 
+    if ($progress == null) {
+        $progress = new \core\progress\none();
+    }
+
     if ($userid) {
         // one raw grade updated for one user
         if (empty($updated_item)) {
@@ -1072,6 +1157,18 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null)
         $depends_on[$gid] = $grade_items[$gid]->depends_on();
     }
 
+    $progresstotal = 0;
+    $progresscurrent = 0;
+
+    // This progress total might not be 100% accurate, because more things might get marked as needsupdate
+    // during the process.
+    foreach ($grade_items as $item) {
+        if ($item->needsupdate) {
+            $progresstotal++;
+        }
+    }
+    $progress->start_progress('regrade_course', $progresstotal);
+
     $errors = array();
     $finalids = array();
     $gids     = array_keys($grade_items);
@@ -1088,6 +1185,16 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null)
                 $finalids[] = $gid; // we can make it final - does not need update
                 continue;
             }
+            $thisprogress = $progresstotal;
+            foreach ($grade_items as $item) {
+                if ($item->needsupdate) {
+                    $thisprogress--;
+                }
+            }
+            // Clip between $progresscurrent and $progresstotal.
+            $thisprogress = max(min($thisprogress, $progresstotal), $progresscurrent);
+            $progress->progress($thisprogress);
+            $progresscurrent = $thisprogress;
 
             $doupdate = true;
             foreach ($depends_on[$gid] as $did) {
@@ -1131,6 +1238,7 @@ function grade_regrade_final_grades($courseid, $userid=null, $updated_item=null)
             break; // Found error.
         }
     }
+    $progress->end_progress();
 
     if (count($errors) == 0) {
         if (empty($userid)) {