MDL-65915 quiz regrading: better progress information
This makes it easier to diagnose problems if the regrade fails in the middle. Along the way, I added one un-declared field to the class, and converted some SQL-construction code to $DB->get_in_or_equal(). I also added the ability to set attributes on the label in html_writer::checkbox.
This commit is contained in:
@@ -1785,10 +1785,12 @@ class html_writer {
|
||||
* @param bool $checked Whether the checkbox is checked
|
||||
* @param string $label The label for the checkbox
|
||||
* @param array $attributes Any attributes to apply to the checkbox
|
||||
* @param array $labelattributes Any attributes to apply to the label, if present
|
||||
* @return string html fragment
|
||||
*/
|
||||
public static function checkbox($name, $value, $checked = true, $label = '', array $attributes = null) {
|
||||
$attributes = (array)$attributes;
|
||||
public static function checkbox($name, $value, $checked = true, $label = '',
|
||||
array $attributes = null, array $labelattributes = null) {
|
||||
$attributes = (array) $attributes;
|
||||
$output = '';
|
||||
|
||||
if ($label !== '' and !is_null($label)) {
|
||||
@@ -1804,7 +1806,9 @@ class html_writer {
|
||||
$output .= self::empty_tag('input', $attributes);
|
||||
|
||||
if ($label !== '' and !is_null($label)) {
|
||||
$output .= self::tag('label', $label, array('for'=>$attributes['id']));
|
||||
$labelattributes = (array) $labelattributes;
|
||||
$labelattributes['for'] = $attributes['id'];
|
||||
$output .= self::tag('label', $label, $labelattributes);
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
||||
@@ -861,6 +861,7 @@ $string['sectionheadingremove'] = 'Remove heading \'{$a}\'';
|
||||
$string['seequestions'] = '(See questions)';
|
||||
$string['select'] = 'Select';
|
||||
$string['selectall'] = 'Select all';
|
||||
$string['selectattempt'] = 'Select attempt';
|
||||
$string['selectcategory'] = 'Select category';
|
||||
$string['selectedattempts'] = 'Selected attempts...';
|
||||
$string['selectmultipleitems'] = 'Select multiple items';
|
||||
|
||||
@@ -109,7 +109,8 @@ abstract class quiz_attempts_report_table extends table_sql {
|
||||
*/
|
||||
public function col_checkbox($attempt) {
|
||||
if ($attempt->attempt) {
|
||||
return '<input type="checkbox" name="attemptid[]" value="'.$attempt->attempt.'" />';
|
||||
return html_writer::checkbox('attemptid[]', $attempt->attempt, false,
|
||||
get_string('selectattempt', 'quiz'), [], ['class' => 'accesshide']);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -64,9 +64,11 @@ $string['regradealldrydogroup'] = 'Regrade attempts ({$a->countregradeneeded}) m
|
||||
$string['regradealldrygroup'] = 'Dry run a full regrade for group \'{$a->groupname}\'';
|
||||
$string['regradeallgroup'] = 'Full regrade for group \'{$a->groupname}\'';
|
||||
$string['regradecomplete'] = 'Regrade completed successfully';
|
||||
$string['regradedsuccessfullyxofy'] = 'Successfully regraded ({$a->done}/{$a->count})';
|
||||
$string['regradeheader'] = 'Regrading';
|
||||
$string['regradeselected'] = 'Regrade selected attempts';
|
||||
$string['regradingattemptxofy'] = 'Regrading attempt ({$a->done}/{$a->count})';
|
||||
$string['regradingattemptxofywithdetails'] = 'Regrading attempt ({$a->done}/{$a->count}) - Attempt {$a->attemptnum} by {$a->name} (id {$a->attemptid})';
|
||||
$string['show'] = 'Show / download';
|
||||
$string['showattempts'] = 'Only show / download attempts';
|
||||
$string['showdetailedmarks'] = 'Marks for each question';
|
||||
|
||||
@@ -39,6 +39,11 @@ require_once($CFG->dirroot . '/mod/quiz/report/overview/overview_table.php');
|
||||
*/
|
||||
class quiz_overview_report extends quiz_attempts_report {
|
||||
|
||||
/**
|
||||
* @var bool whether there are actually students to show, given the options.
|
||||
*/
|
||||
protected $hasgroupstudents;
|
||||
|
||||
public function display($quiz, $cm, $course) {
|
||||
global $DB, $OUTPUT, $PAGE;
|
||||
|
||||
@@ -376,21 +381,22 @@ class quiz_overview_report extends quiz_attempts_report {
|
||||
global $DB;
|
||||
$this->unlock_session();
|
||||
|
||||
$sql = "SELECT quiza.*
|
||||
FROM {quiz_attempts} quiza";
|
||||
$sql = "SELECT quiza.*, " . get_all_user_name_fields(true, 'u') . "
|
||||
FROM {quiz_attempts} quiza
|
||||
JOIN {user} u ON u.id = quiza.userid";
|
||||
$where = "quiz = :qid AND preview = 0";
|
||||
$params = array('qid' => $quiz->id);
|
||||
|
||||
if ($this->hasgroupstudents && !empty($groupstudentsjoins->joins)) {
|
||||
$sql .= "\nJOIN {user} u ON u.id = quiza.userid
|
||||
{$groupstudentsjoins->joins}";
|
||||
$sql .= "\n{$groupstudentsjoins->joins}";
|
||||
$where .= " AND {$groupstudentsjoins->wheres}";
|
||||
$params += $groupstudentsjoins->params;
|
||||
}
|
||||
|
||||
if ($attemptids) {
|
||||
$aids = join(',', $attemptids);
|
||||
$where .= " AND quiza.id IN ({$aids})";
|
||||
list($attemptidcondition, $attemptidparams) = $DB->get_in_or_equal($attemptids, SQL_PARAMS_NAMED);
|
||||
$where .= " AND quiza.id $attemptidcondition";
|
||||
$params += $attemptidparams;
|
||||
}
|
||||
|
||||
$sql .= "\nWHERE {$where}";
|
||||
@@ -407,11 +413,16 @@ class quiz_overview_report extends quiz_attempts_report {
|
||||
'done' => 0,
|
||||
);
|
||||
foreach ($attempts as $attempt) {
|
||||
$this->regrade_attempt($attempt, $dryrun);
|
||||
$a['done']++;
|
||||
$a['attemptnum'] = $attempt->attempt;
|
||||
$a['name'] = fullname($attempt);
|
||||
$a['attemptid'] = $attempt->id;
|
||||
$progressbar->update($a['done'], $a['count'],
|
||||
get_string('regradingattemptxofy', 'quiz_overview', $a));
|
||||
get_string('regradingattemptxofywithdetails', 'quiz_overview', $a));
|
||||
$this->regrade_attempt($attempt, $dryrun);
|
||||
}
|
||||
$progressbar->update($a['done'], $a['count'],
|
||||
get_string('regradedsuccessfullyxofy', 'quiz_overview', $a));
|
||||
|
||||
if (!$dryrun) {
|
||||
$this->update_overall_grades($quiz);
|
||||
@@ -457,8 +468,13 @@ class quiz_overview_report extends quiz_attempts_report {
|
||||
return;
|
||||
}
|
||||
|
||||
$attempts = $DB->get_records_list('quiz_attempts', 'uniqueid',
|
||||
array_keys($attemptquestions));
|
||||
list($uniqueidcondition, $params) = $DB->get_in_or_equal(array_keys($attemptquestions));
|
||||
$attempts = $DB->get_records_sql("
|
||||
SELECT quiza.*, " . get_all_user_name_fields(true, 'u') . "
|
||||
FROM {quiz_attempts} quiza
|
||||
JOIN {user} u ON u.id = quiza.userid
|
||||
WHERE quiza.uniqueid $uniqueidcondition
|
||||
", $params);
|
||||
|
||||
$this->clear_regrade_table($quiz, $groupstudentsjoins);
|
||||
|
||||
@@ -468,11 +484,16 @@ class quiz_overview_report extends quiz_attempts_report {
|
||||
'done' => 0,
|
||||
);
|
||||
foreach ($attempts as $attempt) {
|
||||
$this->regrade_attempt($attempt, false, $attemptquestions[$attempt->uniqueid]);
|
||||
$a['done']++;
|
||||
$a['attemptnum'] = $attempt->attempt;
|
||||
$a['name'] = fullname($attempt);
|
||||
$a['attemptid'] = $attempt->id;
|
||||
$progressbar->update($a['done'], $a['count'],
|
||||
get_string('regradingattemptxofy', 'quiz_overview', $a));
|
||||
get_string('regradingattemptxofywithdetails', 'quiz_overview', $a));
|
||||
$this->regrade_attempt($attempt, false, $attemptquestions[$attempt->uniqueid]);
|
||||
}
|
||||
$progressbar->update($a['done'], $a['count'],
|
||||
get_string('regradedsuccessfullyxofy', 'quiz_overview', $a));
|
||||
|
||||
$this->update_overall_grades($quiz);
|
||||
}
|
||||
|
||||
@@ -78,13 +78,3 @@ Feature: Basic use of the Grades report
|
||||
And I should see "25.00" in the "S1 Student1" "table_row"
|
||||
# Check student2's grade
|
||||
And I should see "100.00" in the "S2 Student2" "table_row"
|
||||
|
||||
# Check regrade and delete attempts.
|
||||
And I set the field with xpath "//tr[contains(normalize-space(.), 'student1@example.com')]//input[@type='checkbox']" to "1"
|
||||
And I press "Regrade selected attempts"
|
||||
And I press "Continue"
|
||||
And I should see "student1@example.com"
|
||||
And I set the field with xpath "//tr[contains(normalize-space(.), 'student1@example.com')]//input[@type='checkbox']" to "1"
|
||||
And I press "Delete selected attempts"
|
||||
And I press "Yes"
|
||||
And I should not see "student1@example.com"
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
@mod @mod_quiz @quiz @quiz_overview @javascript
|
||||
Feature: Regrading quiz attempts using the Grades report
|
||||
In order to be able to correct mistakes I made setting up my quiz
|
||||
As a teacher
|
||||
I need to be able to re-grade attempts after editing questions
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname |
|
||||
| teacher | Mark | Allwright |
|
||||
| student1 | Student | One |
|
||||
| student2 | Student | Two |
|
||||
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 the following "question categories" exist:
|
||||
| contextlevel | reference | name |
|
||||
| Course | C1 | Test questions |
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | idnumber |
|
||||
| quiz | Quiz for testing regrading | C1 | quiz1 |
|
||||
And the following "questions" exist:
|
||||
| questioncategory | qtype | name |
|
||||
| Test questions | truefalse | TF |
|
||||
| Test questions | shortanswer | SA |
|
||||
And quiz "Quiz for testing regrading" contains the following questions:
|
||||
| question | page | maxmark |
|
||||
| TF | 1 | 5.0 |
|
||||
| SA | 1 | 5.0 |
|
||||
And user "student1" has attempted "Quiz for testing regrading" with responses:
|
||||
| slot | response |
|
||||
| 1 | True |
|
||||
| 2 | frog |
|
||||
And user "student2" has attempted "Quiz for testing regrading" with responses:
|
||||
| slot | response |
|
||||
| 1 | True |
|
||||
| 2 | toad |
|
||||
|
||||
Scenario: Regrade all attempts
|
||||
Given I log in as "teacher"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Quiz for testing regrading"
|
||||
And I navigate to "Results > Grades" in current page administration
|
||||
When I press "Regrade all"
|
||||
|
||||
# Note, the order is not defined, so we can only check part of the message.
|
||||
# Also, nothing has changed in the quiz, so the regrade won't alter any scores,
|
||||
# but this is still a useful test that the regrade process completes without errors.
|
||||
Then I should see "Quiz for testing regrading"
|
||||
And I should see "Successfully regraded (2/2)"
|
||||
And I should see "Regrade completed successfully"
|
||||
And I press "Continue"
|
||||
|
||||
# These next tests just serve to check we got back to the report.
|
||||
And I should see "Quiz for testing regrading"
|
||||
And I should see "Overall number of students achieving grade ranges"
|
||||
|
||||
Scenario: Regrade selected attempts
|
||||
Given I log in as "teacher"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Quiz for testing regrading"
|
||||
And I navigate to "Results > Grades" in current page administration
|
||||
When I click on "Select attempt" "checkbox" in the "Student Two" "table_row"
|
||||
|
||||
And I press "Regrade selected attempts"
|
||||
Then I should see "Quiz for testing regrading"
|
||||
And I should see "Successfully regraded (1/1)"
|
||||
And I should see "Regrade completed successfully"
|
||||
And I press "Continue"
|
||||
|
||||
# These next tests just serve to check we got back to the report.
|
||||
And I should see "Quiz for testing regrading"
|
||||
And I should see "Overall number of students achieving grade ranges"
|
||||
|
||||
Scenario: Dry-run a full regrade, then regrade the attempts that will need it.
|
||||
Given I log in as "teacher"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Quiz for testing regrading"
|
||||
When I navigate to "Edit quiz" in current page administration
|
||||
And I follow "Edit question SA"
|
||||
And I set the field "id_fraction_1" to "50%"
|
||||
And I press "id_submitbutton"
|
||||
And I follow "Attempts: 2"
|
||||
And I press "Dry run a full regrade"
|
||||
|
||||
# Note, the order is not defined, so we can only check part of the message.
|
||||
Then I should see "Quiz for testing regrading"
|
||||
And I should see "Successfully regraded (2/2)"
|
||||
And I should see "Regrade completed successfully"
|
||||
And I press "Continue"
|
||||
|
||||
And "Student One" row "Regrade" column of "attempts" table should not contain "Needed"
|
||||
And "Student TwoReview attempt" row "Regrade" column of "attempts" table should contain "Needed"
|
||||
# In the following, the first number is strike-through, and the second is not, but Behat can't see that.
|
||||
# At this point, it is showing what would change.
|
||||
And "Student TwoReview attempt" row "Q. 2/50.00Sort by Q. 2/50.00 Ascending" column of "attempts" table should contain "40.00/25.00"
|
||||
And "Student TwoReview attempt" row "Grade/100.00Sort by Grade/100.00 Ascending" column of "attempts" table should contain "90.00/75.00"
|
||||
And I press "Regrade attempts marked as needing regrading (1)"
|
||||
And I should see "Quiz for testing regrading"
|
||||
And I should see "Successfully regraded (1/1)"
|
||||
And I should see "Regrade completed successfully"
|
||||
And I press "Continue"
|
||||
|
||||
# These next tests just serve to check we got back to the report.
|
||||
And I should see "Quiz for testing regrading"
|
||||
And I should see "Overall number of students achieving grade ranges"
|
||||
# Now, both old-score strike-through and new score plain, are still shown, but now it indicates what did change.
|
||||
And "Student TwoReview attempt" row "Q. 2/50.00Sort by Q. 2/50.00 Ascending" column of "attempts" table should contain "40.00/25.00"
|
||||
And "Student TwoReview attempt" row "Grade/100.00Sort by Grade/100.00 Ascending" column of "attempts" table should contain "90.00/75.00"
|
||||
And "Regrade attempts marked as needing regrading" "button" should not exist
|
||||
Reference in New Issue
Block a user