diff --git a/mod/quiz/db/events.php b/mod/quiz/db/events.php index 84b4b1422b9..0ff77f52866 100644 --- a/mod/quiz/db/events.php +++ b/mod/quiz/db/events.php @@ -35,6 +35,14 @@ $handlers = array( 'handlerfunction' => 'quiz_attempt_submitted_handler', 'schedule' => 'cron', ), + + // Handle our own quiz_attempt_overdue event, to email the student to let them + // know they forgot to submit, and that they have another chance. + 'quiz_attempt_overdue' => array ( + 'handlerfile' => '/mod/quiz/locallib.php', + 'handlerfunction' => 'quiz_attempt_overdue_handler', + 'schedule' => 'cron', + ), ); /* List of events generated by the quiz module, with the fields on the event object. diff --git a/mod/quiz/db/messages.php b/mod/quiz/db/messages.php index e8094070f62..c6ab3905d17 100644 --- a/mod/quiz/db/messages.php +++ b/mod/quiz/db/messages.php @@ -25,14 +25,20 @@ defined('MOODLE_INTERNAL') || die(); -$messageproviders = array ( - // Notify teacher that a student has submitted a quiz attempt - 'submission' => array ( - 'capability' => 'mod/quiz:emailnotifysubmission' +$messageproviders = array( + // Notify teacher that a student has submitted a quiz attempt. + 'submission' => array( + 'capability' => 'mod/quiz:emailnotifysubmission' ), - // Confirm a student's quiz attempt - 'confirmation' => array ( - 'capability' => 'mod/quiz:emailconfirmsubmission' - ) + // Confirm a student's quiz attempt. + 'confirmation' => array( + 'capability' => 'mod/quiz:emailconfirmsubmission' + ), + + // Warning to the student that their quiz attempt is now overdue, if the quiz + // has a grace period. + 'attempt_overdue' => array( + 'capability' => 'mod/quiz:emailwarnoverdue' + ), ); diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php index d207e9e4b6f..340e678612a 100644 --- a/mod/quiz/lang/en/quiz.php +++ b/mod/quiz/lang/en/quiz.php @@ -262,16 +262,27 @@ This message confirms that we have safely received your answers. You can access this quiz at {$a->quizurl}.'; $string['emailconfirmsmall'] = 'Thank you for submitting your answers to \'{$a->quizname}\''; -$string['emailconfirmsubject'] = 'Quiz submission confirmation: {$a->quizname}'; +$string['emailconfirmsubject'] = 'Submission confirmation: {$a->quizname}'; $string['emailnotifybody'] = 'Dear {$a->username}, -{$a->studentname} has completed the quiz +{$a->studentname} has completed \'{$a->quizname}\' ({$a->quizurl}) in course \'{$a->coursename}\' You can review this attempt at {$a->quizreviewurl}.'; -$string['emailnotifysmall'] = '{$a->studentname} has completed {$a->quizname}'; -$string['emailnotifysubject'] = '{$a->studentname} has completed quiz {$a->quizname}'; +$string['emailnotifysmall'] = '{$a->studentname} has completed {$a->quizname}. See {$a->quizreviewurl}'; +$string['emailnotifysubject'] = '{$a->studentname} has completed {$a->quizname}'; +$string['emailoverduebody'] = 'Dear {$a->studentname}, + +You started an attempt at \'{$a->quizname}\' +in course \'{$a->coursename}\', but you never submitted it. + +If you would would still like to submit this attempt, please go to +{$a->attemptsummaryurl} and click the submit button. +You must do this before {$a->attemptgraceend} +otherwise you attempt will not be counted.'; +$string['emailoverduesmall'] = 'You did not submit your attempt at {$a->quizname}. Please go to {$a->attemptsummaryurl} before {$a->attemptgraceend} if you would still like to submit.'; +$string['emailoverduesubject'] = 'Attempt now overdue: {$a->quizname}'; $string['empty'] = 'Empty'; $string['enabled'] = 'Enabled'; $string['endtest'] = 'Finish attempt ...'; diff --git a/mod/quiz/locallib.php b/mod/quiz/locallib.php index 82797a68ee8..0e8fd9092c3 100644 --- a/mod/quiz/locallib.php +++ b/mod/quiz/locallib.php @@ -1255,14 +1255,14 @@ function quiz_send_notification_messages($course, $quiz, $attempt, $context, $cm $a->quizreporturl = $CFG->wwwroot . '/mod/quiz/report.php?id=' . $cm->id; $a->quizreportlink = '' . format_string($quiz->name) . ' report'; - $a->quizreviewurl = $CFG->wwwroot . '/mod/quiz/review.php?attempt=' . $attempt->id; - $a->quizreviewlink = '' . - format_string($quiz->name) . ' review'; $a->quizurl = $CFG->wwwroot . '/mod/quiz/view.php?id=' . $cm->id; $a->quizlink = '' . format_string($quiz->name) . ''; // Attempt info $a->submissiontime = userdate($attempt->timefinish); $a->timetaken = format_time($attempt->timefinish - $attempt->timestart); + $a->quizreviewurl = $CFG->wwwroot . '/mod/quiz/review.php?attempt=' . $attempt->id; + $a->quizreviewlink = '' . + format_string($quiz->name) . ' review'; // Student who sat the quiz info $a->studentidnumber = $submitter->idnumber; $a->studentname = fullname($submitter); @@ -1288,6 +1288,80 @@ function quiz_send_notification_messages($course, $quiz, $attempt, $context, $cm return $allok; } +/** + * Send the notification message when a quiz attempt becomes overdue. + * + * @param object $course the course + * @param object $quiz the quiz + * @param object $attempt this attempt just finished + * @param object $context the quiz context + * @param object $cm the coursemodule for this quiz + */ +function quiz_send_overdue_message($course, $quiz, $attempt, $context, $cm) { + global $CFG, $DB; + + // Do nothing if required objects not present + if (empty($course) or empty($quiz) or empty($attempt) or empty($context)) { + throw new coding_exception('$course, $quiz, $attempt, $context and $cm must all be set.'); + } + + $submitter = $DB->get_record('user', array('id' => $attempt->userid), '*', MUST_EXIST); + + if (!has_capability('mod/quiz:emailwarnoverdue', $context, $submitter, false)) { + return; // Message not required. + } + + // Prepare lots of useful information that admins might want to include in + // the email message. + $quizname = format_string($quiz->name); + + $deadlines = array(); + if ($quiz->timelimit) { + $deadlines[] = $attempt->timestart + $quiz->timelimit; + } + if ($quiz->timeclose) { + $deadlines[] = $quiz->timeclose; + } + $duedate = min($deadlines) + $quiz->graceperiod; + + $a = new stdClass(); + // Course info. + $a->coursename = $course->fullname; + $a->courseshortname = $course->shortname; + // Quiz info. + $a->quizname = $quizname; + $a->quizurl = $CFG->wwwroot . '/mod/quiz/view.php?id=' . $cm->id; + $a->quizlink = '' . $quizname . ''; + // Attempt info. + $a->attemptgraceend = format_time($duedate); + $a->attemptsummaryurl = $CFG->wwwroot . '/mod/quiz/summary.php?attempt=' . $attempt->id; + $a->attemptsummarylink = '' . $quizname . ' review'; + // Student's info. + $a->studentidnumber = $submitter->idnumber; + $a->studentname = fullname($submitter); + $a->studentusername = $submitter->username; + + // Prepare the message. + $eventdata = new stdClass(); + $eventdata->component = 'mod_quiz'; + $eventdata->name = 'attempt_overdue'; + $eventdata->notification = 1; + + $eventdata->userfrom = get_admin(); + $eventdata->userto = $submitter; + $eventdata->subject = get_string('emailoverduesubject', 'quiz', $a); + $eventdata->fullmessage = get_string('emailoverduebody', 'quiz', $a); + $eventdata->fullmessageformat = FORMAT_PLAIN; + $eventdata->fullmessagehtml = ''; + + $eventdata->smallmessage = get_string('emailoverduesmall', 'quiz', $a); + $eventdata->contexturl = $a->quizurl; + $eventdata->contexturlname = $a->quizname; + + // Send the message. + return message_send($eventdata); +} + /** * Handle the quiz_attempt_submitted event. * @@ -1313,6 +1387,36 @@ function quiz_attempt_submitted_handler($event) { get_context_instance(CONTEXT_MODULE, $cm->id), $cm); } +/** + * Handle the quiz_attempt_overdue event. + * + * For quizzes with applicable settings, this sends a message to the user, reminding + * them that they forgot to submit, and that they have another chance to do so. + * + * @param object $event the event object. + */ +function quiz_attempt_overdue_handler($event) { + global $DB; + + $course = $DB->get_record('course', array('id' => $event->courseid)); + $quiz = $DB->get_record('quiz', array('id' => $event->quizid)); + $cm = get_coursemodule_from_id('quiz', $event->cmid, $event->courseid); + $attempt = $DB->get_record('quiz_attempts', array('id' => $event->attemptid)); + + if (!($course && $quiz && $cm && $attempt)) { + // Something has been deleted since the event was raised. Therefore, the + // event is no longer relevant. + return true; + } + + return quiz_send_overdue_message($course, $quiz, $attempt, + get_context_instance(CONTEXT_MODULE, $cm->id), $cm); +} + +/** + * Get the information about the standard quiz JavaScript module. + * @return array a standard jsmodule structure. + */ function quiz_get_js_module() { global $PAGE;