MDL-27030: Fix quiz overview report showing incorrect grades on regraded attempts
[moodle.git] / mod / quiz / report / overview / report.php
CommitLineData
2c3968c4 1<?php
e24ee794
TH
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
2c3968c4 17/**
e24ee794 18 * This file defines the quiz overview report class.
2c3968c4 19 *
e24ee794
TH
20 * @package quiz
21 * @subpackage overview
22 * @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
98f38217 24 */
2c3968c4 25
e24ee794 26
a17b297d
TH
27defined('MOODLE_INTERNAL') || die();
28
e24ee794 29require_once($CFG->dirroot.'/mod/quiz/report/attemptsreport.php');
0217f932 30require_once($CFG->dirroot.'/mod/quiz/report/overview/overviewsettings_form.php');
c35f3afc 31require_once($CFG->dirroot.'/mod/quiz/report/overview/overview_table.php');
7bbe08a2 32
7bbe08a2 33
e24ee794
TH
34/**
35 * Quiz report subclass for the overview (grades) report.
36 *
f7970e3c
TH
37 * @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com}
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
e24ee794
TH
39 */
40class quiz_overview_report extends quiz_attempt_report {
41
c7df5006 42 public function display($quiz, $cm, $course) {
90cd54cb 43 global $CFG, $COURSE, $DB, $OUTPUT;
7bbe08a2 44
98f38217 45 $this->context = get_context_instance(CONTEXT_MODULE, $cm->id);
07a7d859 46
c35f3afc 47 $download = optional_param('download', '', PARAM_ALPHA);
aeb15530 48
e24ee794
TH
49 list($currentgroup, $students, $groupstudents, $allowed) =
50 $this->load_relevant_students($cm);
aeb15530 51
0217f932 52 $pageoptions = array();
53 $pageoptions['id'] = $cm->id;
0217f932 54 $pageoptions['mode'] = 'overview';
55
a6855934 56 $reporturl = new moodle_url('/mod/quiz/report.php', $pageoptions);
334edb71 57 $qmsubselect = quiz_report_qm_filter_select($quiz);
58
e24ee794 59 $mform = new mod_quiz_report_overview_settings($reporturl,
2daffca5
TH
60 array('qmsubselect' => $qmsubselect, 'quiz' => $quiz,
61 'currentgroup' => $currentgroup, 'context' => $this->context));
e24ee794 62
07a2b2f0 63 if ($fromform = $mform->get_data()) {
98f38217 64 $regradeall = false;
65 $regradealldry = false;
66 $regradealldrydo = false;
0217f932 67 $attemptsmode = $fromform->attemptsmode;
07a2b2f0 68 if ($qmsubselect) {
4469159e 69 $qmfilter = $fromform->qmfilter;
70 } else {
71 $qmfilter = 0;
72 }
e24ee794 73 $regradefilter = !empty($fromform->regradefilter);
0217f932 74 set_user_preference('quiz_report_overview_detailedmarks', $fromform->detailedmarks);
75 set_user_preference('quiz_report_pagesize', $fromform->pagesize);
76 $detailedmarks = $fromform->detailedmarks;
77 $pagesize = $fromform->pagesize;
e24ee794 78
0217f932 79 } else {
98f38217 80 $regradeall = optional_param('regradeall', 0, PARAM_BOOL);
81 $regradealldry = optional_param('regradealldry', 0, PARAM_BOOL);
82 $regradealldrydo = optional_param('regradealldrydo', 0, PARAM_BOOL);
7660aa80 83 $attemptsmode = optional_param('attemptsmode', null, PARAM_INT);
07a2b2f0 84 if ($qmsubselect) {
98f38217 85 $qmfilter = optional_param('qmfilter', 0, PARAM_INT);
86 } else {
87 $qmfilter = 0;
88 }
89 $regradefilter = optional_param('regradefilter', 0, PARAM_INT);
0217f932 90 $detailedmarks = get_user_preferences('quiz_report_overview_detailedmarks', 1);
91 $pagesize = get_user_preferences('quiz_report_pagesize', 0);
92 }
e24ee794
TH
93
94 $this->validate_common_options($attemptsmode, $pagesize, $course, $currentgroup);
95 $displayoptions = array();
96 $displayoptions['attemptsmode'] = $attemptsmode;
97 $displayoptions['qmfilter'] = $qmfilter;
98 $displayoptions['regradefilter'] = $regradefilter;
99
25a03faa
TH
100 $mform->set_data($displayoptions +
101 array('detailedmarks' => $detailedmarks, 'pagesize' => $pagesize));
e24ee794
TH
102
103 if (!$this->should_show_grades($quiz)) {
ca359748 104 $detailedmarks = 0;
105 }
e24ee794 106
2fecd85b 107 // We only want to show the checkbox to delete attempts
108 // if the user has permissions and if the report mode is showing attempts.
98f38217 109 $candelete = has_capability('mod/quiz:deleteattempts', $this->context)
f05fedc8 110 && ($attemptsmode != QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO);
2fecd85b 111
f05fedc8 112 if ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) {
e24ee794
TH
113 // This option is only available to users who can access all groups in
114 // groups mode, so setting allowed to empty (which means all quiz attempts
115 // are accessible, is not a security porblem.
f05fedc8
TH
116 $allowed = array();
117 }
118
e24ee794 119 // Load the required questions.
88b3eb8b 120 $questions = quiz_report_get_significant_questions($quiz);
e24ee794
TH
121
122 $table = new quiz_report_overview_table($quiz, $this->context, $qmsubselect,
123 $groupstudents, $students, $detailedmarks, $questions, $candelete,
124 $reporturl, $displayoptions);
125 $filename = quiz_report_download_filename(get_string('overviewfilename', 'quiz_overview'),
126 $course->shortname, $quiz->name);
127 $table->is_downloading($download, $filename,
128 $COURSE->shortname . ' ' . format_string($quiz->name, true));
129 if ($table->is_downloading()) {
130 raise_memory_limit(MEMORY_EXTRA);
131 }
132
133 // Process actions.
db77f410
TH
134 if (empty($currentgroup) || $groupstudents) {
135 if (optional_param('delete', 0, PARAM_BOOL) && confirm_sesskey()) {
136 if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) {
137 require_capability('mod/quiz:deleteattempts', $this->context);
e24ee794 138 $this->delete_selected_attempts($quiz, $cm, $attemptids, $allowed);
db77f410
TH
139 redirect($reporturl->out(false, $displayoptions));
140 }
e24ee794 141
db77f410
TH
142 } else if (optional_param('regrade', 0, PARAM_BOOL) && confirm_sesskey()) {
143 if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) {
e24ee794
TH
144 require_capability('mod/quiz:regrade', $this->context);
145 $this->regrade_attempts($quiz, false, $groupstudents, $attemptids);
db77f410
TH
146 redirect($reporturl->out(false, $displayoptions));
147 }
148 }
149 }
150
db77f410 151 if ($regradeall && confirm_sesskey()) {
e24ee794
TH
152 require_capability('mod/quiz:regrade', $this->context);
153 $this->regrade_attempts($quiz, false, $groupstudents);
154 redirect($reporturl->out(false, $displayoptions), '', 5);
155
db77f410 156 } else if ($regradealldry && confirm_sesskey()) {
e24ee794
TH
157 require_capability('mod/quiz:regrade', $this->context);
158 $this->regrade_attempts($quiz, true, $groupstudents);
159 redirect($reporturl->out(false, $displayoptions), '', 5);
160
db77f410 161 } else if ($regradealldrydo && confirm_sesskey()) {
e24ee794
TH
162 require_capability('mod/quiz:regrade', $this->context);
163 $this->regrade_attempts_needing_it($quiz, $groupstudents);
b9bc2019 164 redirect($reporturl->out(false, $displayoptions), '', 5);
98f38217 165 }
aeb15530 166
e24ee794
TH
167 // Start output.
168 if (!$table->is_downloading()) {
169 // Only print headers if not asked to download data
170 $this->print_header_and_tabs($cm, $course, $quiz, 'overview');
171 }
172
5ada3c8e 173 if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used
c35f3afc 174 if (!$table->is_downloading()) {
ef770037 175 groups_print_activity_menu($cm, $reporturl->out(true, $displayoptions));
970d0fe0 176 }
2d7617c6 177 }
98f38217 178
e24ee794
TH
179 // Print information on the number of existing attempts
180 if (!$table->is_downloading()) { //do not print notices when downloading
181 if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) {
182 echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>';
183 }
184 }
185
3c6185e9
TH
186 $hasquestions = quiz_questions_in_quiz($quiz->questions);
187 if (!$table->is_downloading()) {
188 if (!$hasquestions) {
189 echo quiz_no_questions_message($quiz, $cm, $this->context);
190 } else if (!$students) {
414e7276 191 echo $OUTPUT->notification(get_string('nostudentsyet'));
3c6185e9 192 } else if ($currentgroup && !$groupstudents) {
414e7276
TH
193 echo $OUTPUT->notification(get_string('nostudentsingroup'));
194 }
e24ee794 195
95758992 196 // Print display options
95758992 197 $mform->display();
f6c7f158 198 }
39790bd8 199
3c6185e9
TH
200 $hasstudents = $students && (!$currentgroup || $groupstudents);
201 if ($hasquestions && ($hasstudents || ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL))) {
abe67b24 202 // Construct the SQL
25a03faa
TH
203 $fields = $DB->sql_concat('u.id', "'#'", 'COALESCE(quiza.attempt, 0)') .
204 ' AS uniqueid, ';
55caa1d5 205 if ($qmsubselect) {
206 $fields .=
207 "(CASE " .
208 " WHEN $qmsubselect THEN 1" .
209 " ELSE 0 " .
210 "END) AS gradedattempt, ";
211 }
aeb15530 212
e24ee794
TH
213 list($fields, $from, $where, $params) =
214 $this->base_sql($quiz, $qmsubselect, $qmfilter, $attemptsmode, $allowed);
aeb15530 215
abe67b24 216 $table->set_count_sql("SELECT COUNT(1) FROM $from WHERE $where", $params);
98f38217 217
e24ee794 218 // Test to see if there are any regraded attempts to be listed.
25a03faa
TH
219 $fields .= ", COALESCE((
220 SELECT MAX(qqr.regraded)
221 FROM {quiz_overview_regrades} qqr
222 WHERE qqr.questionusageid = quiza.uniqueid
223 ), -1) AS regraded";
07a2b2f0 224 if ($regradefilter) {
25a03faa
TH
225 $where .= " AND COALESCE((
226 SELECT MAX(qqr.regraded)
227 FROM {quiz_overview_regrades} qqr
228 WHERE qqr.questionusageid = quiza.uniqueid
229 ), -1) <> -1";
98f38217 230 }
abe67b24 231 $table->set_sql($fields, $from, $where, $params);
aeb15530 232
e24ee794
TH
233 if (!$table->is_downloading()) {
234 // Regrade buttons
07a2b2f0 235 if (has_capability('mod/quiz:regrade', $this->context)) {
e24ee794
TH
236 $regradesneeded = $this->count_question_attempts_needing_regrade(
237 $quiz, $groupstudents);
07a2b2f0 238 if ($currentgroup) {
39790bd8 239 $a= new stdClass();
f29e6691 240 $a->groupname = groups_get_group_name($currentgroup);
9101efd3 241 $a->coursestudents = get_string('participants');
e24ee794 242 $a->countregradeneeded = $regradesneeded;
25a03faa
TH
243 $regradealldrydolabel =
244 get_string('regradealldrydogroup', 'quiz_overview', $a);
245 $regradealldrylabel =
246 get_string('regradealldrygroup', 'quiz_overview', $a);
247 $regradealllabel =
248 get_string('regradeallgroup', 'quiz_overview', $a);
f29e6691 249 } else {
25a03faa
TH
250 $regradealldrydolabel =
251 get_string('regradealldrydo', 'quiz_overview', $regradesneeded);
252 $regradealldrylabel =
253 get_string('regradealldry', 'quiz_overview');
254 $regradealllabel =
255 get_string('regradeall', 'quiz_overview');
f29e6691 256 }
25a03faa
TH
257 $displayurl = new moodle_url($reporturl,
258 $displayoptions + array('sesskey' => sesskey()));
f29e6691 259 echo '<div class="mdl-align">';
eb788065 260 echo '<form action="'.$displayurl->out_omit_querystring().'">';
f29e6691 261 echo '<div>';
6ea66ff3 262 echo html_writer::input_hidden_params($displayurl);
f29e6691 263 echo '<input type="submit" name="regradeall" value="'.$regradealllabel.'"/>';
25a03faa
TH
264 echo '<input type="submit" name="regradealldry" value="' .
265 $regradealldrylabel . '"/>';
e24ee794 266 if ($regradesneeded) {
25a03faa
TH
267 echo '<input type="submit" name="regradealldrydo" value="' .
268 $regradealldrydolabel . '"/>';
f29e6691 269 }
270 echo '</div>';
271 echo '</form>';
272 echo '</div>';
273 }
274 // Print information on the grading method
25a03faa
TH
275 if ($strattempthighlight = quiz_report_highlighting_grading_method(
276 $quiz, $qmsubselect, $qmfilter)) {
f29e6691 277 echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>';
278 }
279 }
aeb15530 280
e24ee794
TH
281 // Define table columns
282 $columns = array();
283 $headers = array();
aeb15530 284
e24ee794
TH
285 if (!$table->is_downloading() && $candelete) {
286 $columns[] = 'checkbox';
25a03faa 287 $headers[] = null;
abe67b24 288 }
aeb15530 289
e24ee794 290 $this->add_user_columns($table, $columns, $headers);
aeb15530 291
e24ee794 292 $this->add_time_columns($columns, $headers);
aeb15530 293
abe67b24 294 if ($detailedmarks) {
e24ee794 295 foreach ($questions as $slot => $question) {
abe67b24 296 // Ignore questions of zero length
e24ee794
TH
297 $columns[] = 'qsgrade' . $slot;
298 $header = get_string('qbrief', 'quiz', $question->number);
98f38217 299 if (!$table->is_downloading()) {
e24ee794 300 $header .= '<br />';
98f38217 301 } else {
e24ee794 302 $header .= ' ';
98f38217 303 }
e24ee794 304 $header .= '/' . quiz_rescale_grade($question->maxmark, $quiz, 'question');
98f38217 305 $headers[] = $header;
eacb462e 306 }
abe67b24 307 }
e24ee794
TH
308
309 if (!$table->is_downloading() && has_capability('mod/quiz:regrade', $this->context) &&
310 $this->has_regraded_questions($from, $where, $params)) {
98f38217 311 $columns[] = 'regraded';
312 $headers[] = get_string('regrade', 'quiz_overview');
313 }
aeb15530 314
e24ee794 315 $this->add_grade_columns($quiz, $columns, $headers);
aeb15530 316
25a03faa
TH
317 $this->set_up_table_columns(
318 $table, $columns, $headers, $reporturl, $displayoptions, false);
e24ee794 319 $table->set_attribute('class', 'generaltable generalbox grades');
aeb15530 320
abe67b24 321 $table->out($pagesize, true);
7bbe08a2 322 }
e24ee794
TH
323
324 if (!$table->is_downloading() && $this->should_show_grades($quiz)) {
07a2b2f0 325 if ($currentgroup && $groupstudents) {
f29e6691 326 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
327 $params[] = $quiz->id;
25a03faa
TH
328 if ($DB->record_exists_select('quiz_grades', "userid $usql AND quiz = ?",
329 $params)) {
330 $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
331 array('id' => $quiz->id, 'groupid' => $currentgroup));
332 $graphname = get_string('overviewreportgraphgroup', 'quiz_overview',
333 groups_get_group_name($currentgroup));
90cd54cb 334 echo $OUTPUT->heading($graphname);
25a03faa
TH
335 echo html_writer::tag('div', html_writer::empty_tag('img',
336 array('src' => $imageurl, 'alt' => $graphname)),
337 array('class' => 'graph'));
f29e6691 338 }
339 }
e24ee794 340
07a2b2f0 341 if ($DB->record_exists('quiz_grades', array('quiz'=> $quiz->id))) {
f29e6691 342 $graphname = get_string('overviewreportgraph', 'quiz_overview');
25a03faa
TH
343 $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
344 array('id' => $quiz->id));
90cd54cb 345 echo $OUTPUT->heading($graphname);
25a03faa
TH
346 echo html_writer::tag('div', html_writer::empty_tag('img',
347 array('src' => $imageurl, 'alt' => $graphname)),
348 array('class' => 'graph'));
aad5b0fc 349 }
78517b5a 350 }
7bbe08a2 351 return true;
352 }
e24ee794 353
98f38217 354 /**
e24ee794
TH
355 * Regrade a particular quiz attempt. Either for real ($dryrun = false), or
356 * as a pretend regrade to see which fractions would change. The outcome is
357 * stored in the quiz_overview_regrades table.
358 *
359 * Note, $attempt is not upgraded in the database. The caller needs to do that.
360 * However, $attempt->sumgrades is updated, if this is not a dry run.
361 *
362 * @param object $attempt the quiz attempt to regrade.
f7970e3c 363 * @param bool $dryrun if true, do a pretend regrade, otherwise do it for real.
e24ee794
TH
364 * @param array $slots if null, regrade all questions, otherwise, just regrade
365 * the quetsions with those slots.
98f38217 366 */
e24ee794
TH
367 protected function regrade_attempt($attempt, $dryrun = false, $slots = null) {
368 global $DB;
98f38217 369
e24ee794 370 $transaction = $DB->start_delegated_transaction();
98f38217 371
e24ee794
TH
372 $quba = question_engine::load_questions_usage_by_activity($attempt->uniqueid);
373
374 if (is_null($slots)) {
375 $slots = $quba->get_slots();
98f38217 376 }
e24ee794
TH
377
378 $finished = $attempt->timefinish > 0;
379 foreach ($slots as $slot) {
0ff4bd08 380 $qqr = new stdClass();
e24ee794
TH
381 $qqr->oldfraction = $quba->get_question_fraction($slot);
382
383 $quba->regrade_question($slot, $finished);
384
385 $qqr->newfraction = $quba->get_question_fraction($slot);
386
387 if (abs($qqr->oldfraction - $qqr->newfraction) > 1e-7) {
388 $qqr->questionusageid = $quba->get_id();
389 $qqr->slot = $slot;
390 $qqr->regraded = empty($dryrun);
391 $qqr->timemodified = time();
392 $DB->insert_record('quiz_overview_regrades', $qqr, false);
98f38217 393 }
98f38217 394 }
395
e24ee794
TH
396 if (!$dryrun) {
397 question_engine::save_questions_usage_by_activity($quba);
98f38217 398 }
e24ee794
TH
399
400 $transaction->allow_commit();
98f38217 401 }
e24ee794
TH
402
403 /**
404 * Regrade attempts for this quiz, exactly which attempts are regraded is
405 * controlled by the parameters.
406 * @param object $quiz the quiz settings.
f7970e3c 407 * @param bool $dryrun if true, do a pretend regrade, otherwise do it for real.
e24ee794
TH
408 * @param array $groupstudents blank for all attempts, otherwise regrade attempts
409 * for these users.
410 * @param array $attemptids blank for all attempts, otherwise only regrade
411 * attempts whose id is in this list.
412 */
413 protected function regrade_attempts($quiz, $dryrun = false,
414 $groupstudents = array(), $attemptids = array()) {
98f38217 415 global $DB;
e24ee794
TH
416
417 $where = "quiz = ? AND preview = 0";
418 $params = array($quiz->id);
419
07a2b2f0 420 if ($groupstudents) {
e24ee794
TH
421 list($usql, $uparams) = $DB->get_in_or_equal($groupstudents);
422 $where .= " AND userid $usql";
423 $params = array_merge($params, $uparams);
98f38217 424 }
e24ee794
TH
425
426 if ($attemptids) {
427 list($asql, $aparams) = $DB->get_in_or_equal($attemptids);
428 $where .= " AND id $asql";
429 $params = array_merge($params, $aparams);
98f38217 430 }
98f38217 431
e24ee794
TH
432 $attempts = $DB->get_records_select('quiz_attempts', $where, $params);
433 if (!$attempts) {
434 return;
435 }
98f38217 436
e24ee794 437 $this->clear_regrade_table($quiz, $groupstudents);
98f38217 438
98f38217 439 foreach ($attempts as $attempt) {
e24ee794
TH
440 set_time_limit(30);
441 $this->regrade_attempt($attempt, $dryrun);
442 }
443
444 if (!$dryrun) {
445 $this->update_overall_grades($quiz);
98f38217 446 }
98f38217 447 }
448
e24ee794
TH
449 /**
450 * Regrade those questions in those attempts that are marked as needing regrading
451 * in the quiz_overview_regrades table.
452 * @param object $quiz the quiz settings.
453 * @param array $groupstudents blank for all attempts, otherwise regrade attempts
454 * for these users.
455 */
456 protected function regrade_attempts_needing_it($quiz, $groupstudents) {
98f38217 457 global $DB;
e24ee794
TH
458
459 $where = "quiza.quiz = ? AND quiza.preview = 0 AND qqr.regraded = 0";
460 $params = array($quiz->id);
461
98f38217 462 // Fetch all attempts that need regrading
07a2b2f0 463 if ($groupstudents) {
e24ee794
TH
464 list($usql, $uparams) = $DB->get_in_or_equal($groupstudents);
465 $where .= " AND quiza.userid $usql";
466 $params += $uparams;
98f38217 467 }
23277af8 468
e24ee794
TH
469 $toregrade = $DB->get_records_sql("
470 SELECT quiza.uniqueid, qqr.slot
471 FROM {quiz_attempts} quiza
472 JOIN {quiz_overview_regrades} qqr ON qqr.questionusageid = quiza.uniqueid
473 WHERE $where", $params);
474
475 if (!$toregrade) {
476 return;
98f38217 477 }
478
e24ee794
TH
479 $attemptquestions = array();
480 foreach ($toregrade as $row) {
481 $attemptquestions[$row->uniqueid][] = $row->slot;
98f38217 482 }
25a03faa
TH
483 $attempts = $DB->get_records_list('quiz_attempts', 'uniqueid',
484 array_keys($attemptquestions));
e24ee794
TH
485
486 $this->clear_regrade_table($quiz, $groupstudents);
487
488 foreach ($attempts as $attempt) {
489 set_time_limit(30);
490 $this->regrade_attempt($attempt, false, $attemptquestions[$attempt->uniqueid]);
98f38217 491 }
e24ee794
TH
492
493 $this->update_overall_grades($quiz);
98f38217 494 }
f05fedc8 495
e24ee794
TH
496 /**
497 * Count the number of attempts in need of a regrade.
498 * @param object $quiz the quiz settings.
499 * @param array $groupstudents user ids. If this is given, only data relating
500 * to these users is cleared.
501 */
502 protected function count_question_attempts_needing_regrade($quiz, $groupstudents) {
503 global $DB;
504
505 $usertest = '';
506 $params = array();
507 if ($groupstudents) {
b149b788 508 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
e24ee794 509 $usertest = "quiza.userid $usql AND ";
98f38217 510 }
e24ee794
TH
511
512 $params[] = $quiz->id;
513 $sql = "SELECT COUNT(DISTINCT quiza.id)
514 FROM {quiz_attempts} quiza
515 JOIN {quiz_overview_regrades} qqr ON quiza.uniqueid = qqr.questionusageid
516 WHERE
517 $usertest
518 quiza.quiz = ? AND
519 quiza.preview = 0 AND
520 qqr.regraded = 0";
521 return $DB->count_records_sql($sql, $params);
522 }
523
524 /**
525 * Are there any pending regrades in the table we are going to show?
526 * @param string $from tables used by the main query.
527 * @param string $where where clause used by the main query.
528 * @param array $params required by the SQL.
529 * @return bool whether there are pending regrades.
530 */
531 protected function has_regraded_questions($from, $where, $params) {
532 global $DB;
533 $qubaids = new qubaid_join($from, 'uniqueid', $where, $params);
534 return $DB->record_exists_select('quiz_overview_regrades',
25a03faa
TH
535 'questionusageid ' . $qubaids->usage_id_in(),
536 $qubaids->usage_id_in_params());
98f38217 537 }
f05fedc8 538
e24ee794
TH
539 /**
540 * Remove all information about pending/complete regrades from the database.
541 * @param object $quiz the quiz settings.
542 * @param array $groupstudents user ids. If this is given, only data relating
543 * to these users is cleared.
544 */
545 protected function clear_regrade_table($quiz, $groupstudents) {
98f38217 546 global $DB;
e24ee794
TH
547
548 // Fetch all attempts that need regrading
549 $where = '';
550 $params = array();
07a2b2f0 551 if ($groupstudents) {
98f38217 552 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
e24ee794 553 $where = "userid $usql AND ";
98f38217 554 }
aeb15530 555
98f38217 556 $params[] = $quiz->id;
e24ee794
TH
557 $DB->delete_records_select('quiz_overview_regrades',
558 "questionusageid IN (
559 SELECT uniqueid
560 FROM {quiz_attempts}
561 WHERE $where quiz = ?
562 )", $params);
563 }
98f38217 564
e24ee794
TH
565 /**
566 * Update the final grades for all attempts. This method is used following
567 * a regrade.
568 * @param object $quiz the quiz settings.
569 * @param array $userids only update scores for these userids.
570 * @param array $attemptids attemptids only update scores for these attempt ids.
571 */
572 protected function update_overall_grades($quiz) {
573 quiz_update_all_attempt_sumgrades($quiz);
574 quiz_update_all_final_grades($quiz);
575 quiz_update_grades($quiz);
98f38217 576 }
7bbe08a2 577}