Skip to content

Commit

Permalink
MDL-3030 quiz overdue handling: test state, not timefinish where appl…
Browse files Browse the repository at this point in the history
…icable.
  • Loading branch information
timhunt committed Apr 27, 2012
1 parent 3e77b60 commit be18f58
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 42 deletions.
4 changes: 2 additions & 2 deletions mod/quiz/accessmanager.php
Expand Up @@ -462,8 +462,8 @@ public function back_to_view_page($output, $message = '') {
*/
public function make_review_link($attempt, $reviewoptions, $output) {

// If review of responses is not allowed, or the attempt is still open, don't link.
if (!$attempt->timefinish) {
// If the attempt is still open, don't link.
if (in_array($attempt->state, array(quiz_attempt::IN_PROGRESS, quiz_attempt::OVERDUE))) {
return $output->no_review_message('');
}

Expand Down
16 changes: 4 additions & 12 deletions mod/quiz/attemptlib.php
Expand Up @@ -513,16 +513,7 @@ public static function create_from_usage_id($usageid) {
* @return string the human-readable state name.
*/
public static function state_name($state) {
switch ($state) {
case quiz_attempt::IN_PROGRESS:
return get_string('stateinprogress', 'quiz');
case quiz_attempt::OVERDUE:
return get_string('stateoverdue', 'quiz');
case quiz_attempt::FINISHED:
return get_string('statefinished', 'quiz');
case quiz_attempt::ABANDONED:
return get_string('stateabandoned', 'quiz');
}
return quiz_attempt_state_name($state);
}

private function determine_layout() {
Expand Down Expand Up @@ -1321,7 +1312,7 @@ public function process_submitted_actions($timestamp, $becomingoverdue = false)
$DB->update_record('quiz_attempts', $this->attempt);
}

if (!$this->is_preview() && $this->attempt->timefinish) {
if (!$this->is_preview() && $this->attempt->state == quiz_attempt::FINISHED) {
quiz_save_best_grade($this->get_quiz(), $this->get_userid());
}

Expand Down Expand Up @@ -1435,7 +1426,8 @@ protected function fire_state_transition_event($event, $timestamp) {
}

if ($event == 'quiz_attempt_submitted') {
$eventdata->timefinish = $timestamp; // Backwards compatibility.
// Backwards compatibility for this event type. $eventdata->timestamp is now preferred.
$eventdata->timefinish = $timestamp;
}

events_trigger($event, $eventdata);
Expand Down
9 changes: 5 additions & 4 deletions mod/quiz/lib.php
Expand Up @@ -402,7 +402,6 @@ function quiz_user_outline($course, $user, $mod, $quiz) {
* Print a detailed representation of what a user has done with
* a given particular instance of this module, for user activity reports.
*
* @global object
* @param object $course
* @param object $user
* @param object $mod
Expand All @@ -411,7 +410,8 @@ function quiz_user_outline($course, $user, $mod, $quiz) {
*/
function quiz_user_complete($course, $user, $mod, $quiz) {
global $DB, $CFG, $OUTPUT;
require_once("$CFG->libdir/gradelib.php");
require_once($CFG->libdir . '/gradelib.php');
require_once($CFG->libdir . '/mod/quiz/locallib.php');

$grades = grade_get_grades($course->id, 'mod', 'quiz', $quiz->id, $user->id);
if (!empty($grades->items[0]->grades)) {
Expand All @@ -426,8 +426,8 @@ function quiz_user_complete($course, $user, $mod, $quiz) {
array('userid' => $user->id, 'quiz' => $quiz->id), 'attempt')) {
foreach ($attempts as $attempt) {
echo get_string('attempt', 'quiz').' '.$attempt->attempt.': ';
if ($attempt->timefinish == 0) {
print_string('unfinished');
if ($attempt->state != quiz_attempt::FINISHED) {
echo quiz_attempt_state_name($attempt->state);
} else {
echo quiz_format_grade($quiz, $attempt->sumgrades) . '/' .
quiz_format_grade($quiz, $quiz->sumgrades);
Expand All @@ -445,6 +445,7 @@ function quiz_user_complete($course, $user, $mod, $quiz) {
* Quiz periodic clean-up tasks.
*/
function quiz_cron() {
global $CFG;

// Run cron for our sub-plugin types.
cron_execute_plugin_type('quiz', 'quiz reports');
Expand Down
51 changes: 39 additions & 12 deletions mod/quiz/locallib.php
Expand Up @@ -105,6 +105,7 @@ function quiz_create_attempt($quiz, $attemptnumber, $lastattempt, $timenow, $isp
$attempt->timestart = $timenow;
$attempt->timefinish = 0;
$attempt->timemodified = $timenow;
$attempt->state = quiz_attempt::IN_PROGRESS;

// If this is a preview, mark it as such.
if ($ispreview) {
Expand Down Expand Up @@ -445,8 +446,9 @@ function quiz_update_all_attempt_sumgrades($quiz) {
sumgrades = (
{$dm->sum_usage_marks_subquery('uniqueid')}
)
WHERE quiz = :quizid AND timefinish <> 0";
$DB->execute($sql, array('timenow' => $timenow, 'quizid' => $quiz->id));
WHERE quiz = :quizid AND state = :finishedstate";
$DB->execute($sql, array('timenow' => $timenow, 'quizid' => $quiz->id,
'finishedstate' => quiz_attempt::FINISHED));
}

/**
Expand Down Expand Up @@ -613,7 +615,7 @@ function quiz_update_all_final_grades($quiz) {
return;
}

$param = array('iquizid' => $quiz->id);
$param = array('iquizid' => $quiz->id, 'istatefinished' => quiz_attempt::FINISHED);
$firstlastattemptjoin = "JOIN (
SELECT
iquiza.userid,
Expand All @@ -623,7 +625,7 @@ function quiz_update_all_final_grades($quiz) {
FROM {quiz_attempts} iquiza
WHERE
iquiza.timefinish <> 0 AND
iquiza.state = :istatefinished
iquiza.preview = 0 AND
iquiza.quiz = :iquizid
Expand Down Expand Up @@ -670,13 +672,15 @@ function quiz_update_all_final_grades($quiz) {
$param['quizid2'] = $quiz->id;
$param['quizid3'] = $quiz->id;
$param['quizid4'] = $quiz->id;
$param['statefinished'] = quiz_attempt::FINISHED;
$param['statefinished2'] = quiz_attempt::FINISHED;
$finalgradesubquery = "
SELECT quiza.userid, $finalgrade AS newgrade
FROM {quiz_attempts} quiza
$join
WHERE
$where
quiza.timefinish <> 0 AND
quiza.quiza.state = :statefinished AND
quiza.preview = 0 AND
quiza.quiz = :quizid3
GROUP BY quiza.userid";
Expand All @@ -692,7 +696,7 @@ function quiz_update_all_final_grades($quiz) {
SELECT DISTINCT userid
FROM {quiz_attempts} quiza2
WHERE
quiza2.timefinish <> 0 AND
quiza2.quiza.state = :statefinished2 AND
quiza2.preview = 0 AND
quiza2.quiz = :quizid2
) users
Expand Down Expand Up @@ -818,6 +822,25 @@ function quiz_get_overdue_handling_options() {
);
}

/**
* @param string $state one of the state constants like IN_PROGRESS.
* @return string the human-readable state name.
*/
function quiz_attempt_state_name($state) {
switch ($state) {
case quiz_attempt::IN_PROGRESS:
return get_string('stateinprogress', 'quiz');
case quiz_attempt::OVERDUE:
return get_string('stateoverdue', 'quiz');
case quiz_attempt::FINISHED:
return get_string('statefinished', 'quiz');
case quiz_attempt::ABANDONED:
return get_string('stateabandoned', 'quiz');
default:
throw new coding_exception('Unknown quiz attempt state.');
}
}

/// Other quiz functions ////////////////////////////////////////////////////

/**
Expand Down Expand Up @@ -950,14 +973,15 @@ function quiz_get_flag_option($attempt, $context) {
}

/**
* Work out what state this quiz attempt is in.
* Work out what state this quiz attempt is in - in the sense used by
* quiz_get_review_options, not in the sense of $attempt->state.
* @param object $quiz the quiz settings
* @param object $attempt the quiz_attempt database row.
* @return int one of the mod_quiz_display_options::DURING,
* IMMEDIATELY_AFTER, LATER_WHILE_OPEN or AFTER_CLOSE constants.
*/
function quiz_attempt_state($quiz, $attempt) {
if ($attempt->timefinish == 0) {
if ($attempt->state != quiz_attempt::FINISHED) {
return mod_quiz_display_options::DURING;
} else if (time() < $attempt->timefinish + 120) {
return mod_quiz_display_options::IMMEDIATELY_AFTER;
Expand Down Expand Up @@ -989,7 +1013,7 @@ function quiz_get_review_options($quiz, $attempt, $context) {
}

// Show a link to the comment box only for closed attempts
if (!empty($attempt->id) && $attempt->timefinish && !$attempt->preview &&
if (!empty($attempt->id) && $attempt->state == quiz_attempt::FINISHED && !$attempt->preview &&
!is_null($context) && has_capability('mod/quiz:grade', $context)) {
$options->manualcomment = question_display_options::VISIBLE;
$options->manualcommentlink = new moodle_url('/mod/quiz/comment.php',
Expand Down Expand Up @@ -1517,14 +1541,17 @@ protected static function extract($bitmask, $bit,
class qubaids_for_quiz extends qubaid_join {
public function __construct($quizid, $includepreviews = true, $onlyfinished = false) {
$where = 'quiza.quiz = :quizaquiz';
$params = array('quizaquiz' => $quizid);

if (!$includepreviews) {
$where .= ' AND preview = 0';
}

if ($onlyfinished) {
$where .= ' AND timefinish <> 0';
$where .= ' AND state == :statefinished';
$params['statefinished'] = quiz_attempt::FINISHED;
}

parent::__construct('{quiz_attempts} quiza', 'quiza.uniqueid', $where,
array('quizaquiz' => $quizid));
parent::__construct('{quiz_attempts} quiza', 'quiza.uniqueid', $where, $params);
}
}
7 changes: 2 additions & 5 deletions mod/quiz/report/attemptsreport_table.php
Expand Up @@ -202,7 +202,7 @@ public function col_duration($attempt) {
* @return string HTML content to go inside the td.
*/
public function col_feedbacktext($attempt) {
if (!$attempt->timefinish) {
if ($attempt->state != quiz_attempt::FINISHED) {
return '-';
}

Expand Down Expand Up @@ -371,10 +371,7 @@ public function base_sql($reportstudents) {
CASE WHEN quiza.timefinish = 0 THEN null
WHEN quiza.timefinish > quiza.timestart THEN quiza.timefinish - quiza.timestart
ELSE 0 END AS duration';
// To explain that last bit, in MySQL, qa.timestart and qa.timefinish
// are unsigned. Since MySQL 5.5.5, when they introduced strict mode,
// subtracting a larger unsigned int from a smaller one gave an error.
// Therefore, we avoid doing that. timefinish can be non-zero and less
// To explain that last bit, timefinish can be non-zero and less
// than timestart when you have two load-balanced servers with very
// badly synchronised clocks, and a student does a really quick attempt.

Expand Down
7 changes: 4 additions & 3 deletions mod/quiz/report/grading/report.php
Expand Up @@ -162,8 +162,8 @@ protected function get_qubaids_condition() {

$where = "quiza.quiz = :mangrquizid AND
quiza.preview = 0 AND
quiza.timefinish <> 0";
$params = array('mangrquizid' => $this->cm->instance);
quiza.state = :statefinished";
$params = array('mangrquizid' => $this->cm->instance, 'statefinished' => quiz_attempt::FINISHED);

$currentgroup = groups_get_activity_group($this->cm, true);
if ($currentgroup) {
Expand All @@ -187,13 +187,14 @@ protected function load_attempts_by_usage_ids($qubaids) {
global $DB;

list($asql, $params) = $DB->get_in_or_equal($qubaids);
$params[] = quiz_attempt::FINISHED;
$params[] = $this->quiz->id;

$attemptsbyid = $DB->get_records_sql("
SELECT quiza.*, u.firstname, u.lastname, u.idnumber
FROM {quiz_attempts} quiza
JOIN {user} u ON u.id = quiza.userid
WHERE quiza.uniqueid $asql AND quiza.timefinish <> 0 AND quiza.quiz = ?",
WHERE quiza.uniqueid $asql AND quiza.state == ? AND quiza.quiz = ?",
$params);

$attempts = array();
Expand Down
2 changes: 1 addition & 1 deletion mod/quiz/report/overview/overview_table.php
Expand Up @@ -180,7 +180,7 @@ protected function submit_buttons() {
}

public function col_sumgrades($attempt) {
if (!$attempt->timefinish) {
if ($attempt->state != quiz_attempt::FINISHED) {
return '-';
}

Expand Down
2 changes: 1 addition & 1 deletion mod/quiz/report/overview/report.php
Expand Up @@ -321,7 +321,7 @@ protected function regrade_attempt($attempt, $dryrun = false, $slots = null) {
$slots = $quba->get_slots();
}

$finished = $attempt->timefinish > 0;
$finished = $attempt->state == quiz_attempt::FINISHED;
foreach ($slots as $slot) {
$qqr = new stdClass();
$qqr->oldfraction = $quba->get_question_fraction($slot);
Expand Down
2 changes: 1 addition & 1 deletion mod/quiz/report/responses/responses_table.php
Expand Up @@ -63,7 +63,7 @@ public function build_table() {
}

public function col_sumgrades($attempt) {
if (!$attempt->timefinish) {
if ($attempt->state == quiz_attempt::FINISHED) {
return '-';
}

Expand Down
2 changes: 1 addition & 1 deletion mod/quiz/review.php
Expand Up @@ -184,7 +184,7 @@
$grade = quiz_rescale_grade($attempt->sumgrades, $quiz, false);
if ($options->marks >= question_display_options::MARK_AND_MAX && quiz_has_grades($quiz)) {

if (!$attempt->timefinish) {
if ($attempt->state != quiz_attempt::FINISHED) {
$summarydata['grade'] = array(
'title' => get_string('grade', 'quiz'),
'content' => get_string('attemptstillinprogress', 'quiz'),
Expand Down

0 comments on commit be18f58

Please sign in to comment.