diff --git a/grade/edit/tree/index.php b/grade/edit/tree/index.php index 672888acb1e..49ab967ecac 100644 --- a/grade/edit/tree/index.php +++ b/grade/edit/tree/index.php @@ -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 ''; 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); diff --git a/grade/export/lib.php b/grade/export/lib.php index bf7b981819a..755fa8ad80d 100644 --- a/grade/export/lib.php +++ b/grade/export/lib.php @@ -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'); } } diff --git a/grade/lib.php b/grade/lib.php index 52c296d4d83..66cf003698b 100644 --- a/grade/lib.php +++ b/grade/lib.php @@ -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) { diff --git a/grade/report/grader/index.php b/grade/report/grader/index.php index f15efe25979..7885fdc90d8 100644 --- a/grade/report/grader/index.php +++ b/grade/report/grader/index.php @@ -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); diff --git a/grade/report/outcomes/index.php b/grade/report/outcomes/index.php index cc809abd889..092373ade80 100644 --- a/grade/report/outcomes/index.php +++ b/grade/report/outcomes/index.php @@ -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(); diff --git a/grade/report/overview/index.php b/grade/report/overview/index.php index e46885cb065..14eef55bc6b 100644 --- a/grade/report/overview/index.php +++ b/grade/report/overview/index.php @@ -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. diff --git a/grade/report/singleview/index.php b/grade/report/singleview/index.php index be9461ba13b..9d6ab824d3e 100644 --- a/grade/report/singleview/index.php +++ b/grade/report/singleview/index.php @@ -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); diff --git a/grade/report/singleview/tests/behat/bulk_insert_grades.feature b/grade/report/singleview/tests/behat/bulk_insert_grades.feature index a06a1821819..218a8320295 100644 --- a/grade/report/singleview/tests/behat/bulk_insert_grades.feature +++ b/grade/report/singleview/tests/behat/bulk_insert_grades.feature @@ -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" diff --git a/grade/report/singleview/tests/behat/singleview.feature b/grade/report/singleview/tests/behat/singleview.feature index 8036568a660..f12404d80ec 100644 --- a/grade/report/singleview/tests/behat/singleview.feature +++ b/grade/report/singleview/tests/behat/singleview.feature @@ -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" diff --git a/grade/report/singleview/tests/screen_test.php b/grade/report/singleview/tests/screen_test.php index 2476d08a04f..eed99219f38 100644 --- a/grade/report/singleview/tests/screen_test.php +++ b/grade/report/singleview/tests/screen_test.php @@ -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 +} diff --git a/grade/report/user/index.php b/grade/report/user/index.php index 149879c328b..1e8460e24a0 100644 --- a/grade/report/user/index.php +++ b/grade/report/user/index.php @@ -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 diff --git a/grade/report/user/lib.php b/grade/report/user/lib.php index 0f35f8289c4..65f66a6ebca 100644 --- a/grade/report/user/lib.php +++ b/grade/report/user/lib.php @@ -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 diff --git a/grade/report/user/tests/behat/view_usereport.feature b/grade/report/user/tests/behat/view_usereport.feature index b4051b86d58..9bc1f8f2fa8 100644 --- a/grade/report/user/tests/behat/view_usereport.feature +++ b/grade/report/user/tests/behat/view_usereport.feature @@ -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" diff --git a/grade/tests/behat/grade_UI_settings.feature b/grade/tests/behat/grade_UI_settings.feature index 72b1feba548..e01b9282c7c 100644 --- a/grade/tests/behat/grade_UI_settings.feature +++ b/grade/tests/behat/grade_UI_settings.feature @@ -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" diff --git a/grade/tests/behat/grade_override_letter.feature b/grade/tests/behat/grade_override_letter.feature index 12ac7d38795..6abdcb9e0d4 100644 --- a/grade/tests/behat/grade_override_letter.feature +++ b/grade/tests/behat/grade_override_letter.feature @@ -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 % | Ω | diff --git a/grade/tests/behat/grade_point_maximum.feature b/grade/tests/behat/grade_point_maximum.feature index 107030221f2..c750f819603 100644 --- a/grade/tests/behat/grade_point_maximum.feature +++ b/grade/tests/behat/grade_point_maximum.feature @@ -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" diff --git a/grade/tests/behat/grade_scales_aggregation.feature b/grade/tests/behat/grade_scales_aggregation.feature index 2c74e52dd00..b866294391f 100644 --- a/grade/tests/behat/grade_scales_aggregation.feature +++ b/grade/tests/behat/grade_scales_aggregation.feature @@ -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" diff --git a/grade/tests/behat/grade_single_item_scales.feature b/grade/tests/behat/grade_single_item_scales.feature index 190e1f7d5d0..ed3a96ab04a 100644 --- a/grade/tests/behat/grade_single_item_scales.feature +++ b/grade/tests/behat/grade_single_item_scales.feature @@ -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 "" And I press "Save changes" And I follow "Edit Sub category 1" - And I expand all fieldsets - And I set the field "Aggregation" to "" - And I set the field "Category name" to "Sub category ()" - # 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 | | + | Category name | Sub category () | 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! | | | 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! | | | Sub category () total. | | 0–100 | - | | Course total. | | 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 () total. | 100.00 | - | Course total. | 100.00 | + | Course total. | 100.00 | Examples: | aggregation | contrib1 | cattotal1 | coursetotal1 | catavg | overallavg | diff --git a/grade/tests/behat/grade_to_pass.feature b/grade/tests/behat/grade_to_pass.feature index 34360b1e09f..7125b6232b2 100644 --- a/grade/tests/behat/grade_to_pass.feature +++ b/grade/tests/behat/grade_to_pass.feature @@ -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" diff --git a/lang/en/error.php b/lang/en/error.php index 32aded39cda..2dc689f8214 100644 --- a/lang/en/error.php +++ b/lang/en/error.php @@ -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'; diff --git a/lang/en/grades.php b/lang/en/grades.php index 4089b5e4f65..f37a5fe5e66 100644 --- a/lang/en/grades.php +++ b/lang/en/grades.php @@ -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'; diff --git a/lib/classes/progress/display.php b/lib/classes/progress/display.php index 4e3b46ff501..b7974bc0b56 100644 --- a/lib/classes/progress/display.php +++ b/lib/classes/progress/display.php @@ -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. diff --git a/lib/gradelib.php b/lib/gradelib.php index 6dfa2279d75..c50ecd9abe9 100644 --- a/lib/gradelib.php +++ b/lib/gradelib.php @@ -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)) {