Skip to content

Commit

Permalink
MDL-72137 Quiz: Quiz submission email notification update
Browse files Browse the repository at this point in the history
Quiz submission notifications: separate out User versus System
  • Loading branch information
nguyenphuctien committed Aug 23, 2021
1 parent 1464843 commit dd6fd52
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 14 deletions.
20 changes: 11 additions & 9 deletions mod/quiz/attemptlib.php
Expand Up @@ -2011,7 +2011,7 @@ public function handle_if_time_expired($timestamp, $studentisonline) {
// Transition to the appropriate state.
switch ($this->quizobj->get_quiz()->overduehandling) {
case 'autosubmit':
$this->process_finish($timestamp, false, $studentisonline ? $timestamp : $timeclose);
$this->process_finish($timestamp, false, $studentisonline ? $timestamp : $timeclose, $studentisonline);
return;

case 'graceperiod':
Expand Down Expand Up @@ -2183,8 +2183,9 @@ public function save_question_flags() {
* POST request are stored to be graded, before the attempt is finished.
* @param ?int $timefinish if set, use this as the finish time for the attempt.
* (otherwise use $timestamp as the finish time as well).
* @param bool $studentisonline is the student currently interacting with Moodle?
*/
public function process_finish($timestamp, $processsubmitted, $timefinish = null) {
public function process_finish($timestamp, $processsubmitted, $timefinish = null, $studentisonline = false) {
global $DB;

$transaction = $DB->start_delegated_transaction();
Expand All @@ -2207,7 +2208,7 @@ public function process_finish($timestamp, $processsubmitted, $timefinish = null
quiz_save_best_grade($this->get_quiz(), $this->attempt->userid);

// Trigger event.
$this->fire_state_transition_event('\mod_quiz\event\attempt_submitted', $timestamp);
$this->fire_state_transition_event('\mod_quiz\event\attempt_submitted', $timestamp, $studentisonline);

// Tell any access rules that care that the attempt is over.
$this->get_access_manager($timestamp)->current_attempt_finished();
Expand Down Expand Up @@ -2246,7 +2247,7 @@ public function process_going_overdue($timestamp, $studentisonline) {
$this->attempt->timecheckstate = $timestamp;
$DB->update_record('quiz_attempts', $this->attempt);

$this->fire_state_transition_event('\mod_quiz\event\attempt_becameoverdue', $timestamp);
$this->fire_state_transition_event('\mod_quiz\event\attempt_becameoverdue', $timestamp, $studentisonline);

$transaction->allow_commit();

Expand All @@ -2268,7 +2269,7 @@ public function process_abandon($timestamp, $studentisonline) {
$this->attempt->timecheckstate = null;
$DB->update_record('quiz_attempts', $this->attempt);

$this->fire_state_transition_event('\mod_quiz\event\attempt_abandoned', $timestamp);
$this->fire_state_transition_event('\mod_quiz\event\attempt_abandoned', $timestamp, $studentisonline);

$transaction->allow_commit();
}
Expand All @@ -2278,8 +2279,9 @@ public function process_abandon($timestamp, $studentisonline) {
*
* @param string $eventclass the event class name.
* @param int $timestamp the timestamp to include in the event.
* @param bool $studentisonline is the student currently interacting with Moodle?
*/
protected function fire_state_transition_event($eventclass, $timestamp) {
protected function fire_state_transition_event($eventclass, $timestamp, $studentisonline) {
global $USER;
$quizrecord = $this->get_quiz();
$params = array(
Expand All @@ -2289,10 +2291,10 @@ protected function fire_state_transition_event($eventclass, $timestamp) {
'relateduserid' => $this->attempt->userid,
'other' => array(
'submitterid' => CLI_SCRIPT ? null : $USER->id,
'quizid' => $quizrecord->id
'quizid' => $quizrecord->id,
'studentisonline' => $studentisonline
)
);

$event = $eventclass::create($params);
$event->add_record_snapshot('quiz', $this->get_quiz());
$event->add_record_snapshot('quiz_attempts', $this->get_attempt());
Expand Down Expand Up @@ -2462,7 +2464,7 @@ public function process_attempt($timenow, $finishattempt, $timeup, $thispage) {
if ($becomingabandoned) {
$this->process_abandon($timenow, true);
} else {
$this->process_finish($timenow, !$toolate, $toolate ? $timeclose : $timenow);
$this->process_finish($timenow, !$toolate, $toolate ? $timeclose : $timenow, true);
}

} catch (question_out_of_sequence_exception $e) {
Expand Down
1 change: 1 addition & 0 deletions mod/quiz/classes/event/attempt_submitted.php
Expand Up @@ -32,6 +32,7 @@
*
* - int submitterid: id of submitter (null when trigged by CLI script).
* - int quizid: (optional) the id of the quiz.
* - bool studentisonline: is the student currently interacting with Moodle?
* }
*
* @package mod_quiz
Expand Down
8 changes: 8 additions & 0 deletions mod/quiz/lang/en/quiz.php
Expand Up @@ -311,8 +311,16 @@
This message confirms that your answers have been saved.
You can access this quiz at {$a->quizurl}.';
$string['emailconfirmbodyautosubmit'] = 'Hi {$a->username},
The time for the quiz \'{$a->quizname}\' in the course \'{$a->coursename}\' expired. Your answers were submitted automatically at {$a->submissiontime}.
This message confirms that your answers have been saved.
You can access this quiz at {$a->quizurl}.';
$string['emailconfirmsmall'] = 'Thank you for submitting your answers to \'{$a->quizname}\'';
$string['emailconfirmautosubmitsmall'] = 'Thank you for submitting your answers to \'{$a->quizname}\'';
$string['emailconfirmsubject'] = 'Submission confirmation: {$a->quizname}';
$string['emailnotifybody'] = 'Hi {$a->username},
Expand Down
19 changes: 14 additions & 5 deletions mod/quiz/locallib.php
Expand Up @@ -1584,10 +1584,11 @@ function quiz_get_combined_reviewoptions($quiz, $attempts) {
*
* @param object $a lots of useful information that can be used in the message
* subject and body.
* @param bool $studentisonline is the student currently interacting with Moodle?
*
* @return int|false as for {@link message_send()}.
*/
function quiz_send_confirmation($recipient, $a) {
function quiz_send_confirmation($recipient, $a, $studentisonline) {

// Add information about the recipient to $a.
// Don't do idnumber. we want idnumber to be the submitter's idnumber.
Expand All @@ -1604,7 +1605,13 @@ function quiz_send_confirmation($recipient, $a) {
$eventdata->userfrom = core_user::get_noreply_user();
$eventdata->userto = $recipient;
$eventdata->subject = get_string('emailconfirmsubject', 'quiz', $a);
$eventdata->fullmessage = get_string('emailconfirmbody', 'quiz', $a);

if ($studentisonline) {
$eventdata->fullmessage = get_string('emailconfirmbody', 'quiz', $a);
} else {
$eventdata->fullmessage = get_string('emailconfirmbodyautosubmit', 'quiz', $a);
}

$eventdata->fullmessageformat = FORMAT_PLAIN;
$eventdata->fullmessagehtml = '';

Expand Down Expand Up @@ -1676,10 +1683,11 @@ function quiz_send_notification($recipient, $submitter, $a) {
* @param object $attempt this attempt just finished
* @param object $context the quiz context
* @param object $cm the coursemodule for this quiz
* @param bool $studentisonline is the student currently interacting with Moodle?
*
* @return bool true if all necessary messages were sent successfully, else false.
*/
function quiz_send_notification_messages($course, $quiz, $attempt, $context, $cm) {
function quiz_send_notification_messages($course, $quiz, $attempt, $context, $cm, $studentisonline) {
global $CFG, $DB;

// Do nothing if required objects not present.
Expand Down Expand Up @@ -1760,7 +1768,7 @@ function quiz_send_notification_messages($course, $quiz, $attempt, $context, $cm
// some but not all messages, and then try again later, then teachers may get
// duplicate messages, but the student will always get exactly one.
if ($sendconfirm) {
$allok = $allok && quiz_send_confirmation($submitter, $a);
$allok = $allok && quiz_send_confirmation($submitter, $a, $studentisonline);
}

return $allok;
Expand Down Expand Up @@ -1858,6 +1866,7 @@ function quiz_attempt_submitted_handler($event) {
$attempt = $event->get_record_snapshot('quiz_attempts', $event->objectid);
$quiz = $event->get_record_snapshot('quiz', $attempt->quiz);
$cm = get_coursemodule_from_id('quiz', $event->get_context()->instanceid, $event->courseid);
$eventdata = $event->get_data();

if (!($course && $quiz && $cm && $attempt)) {
// Something has been deleted since the event was raised. Therefore, the
Expand All @@ -1872,7 +1881,7 @@ function quiz_attempt_submitted_handler($event) {
$completion->update_state($cm, COMPLETION_COMPLETE, $event->userid);
}
return quiz_send_notification_messages($course, $quiz, $attempt,
context_module::instance($cm->id), $cm);
context_module::instance($cm->id), $cm, $eventdata['other']['studentisonline']);
}

/**
Expand Down
53 changes: 53 additions & 0 deletions mod/quiz/tests/locallib_test.php
Expand Up @@ -941,4 +941,57 @@ public function test_quiz_override_summary() {
$this->assertEquals('Settings overrides exist (Groups: 2, Users: 2)',
html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false));
}

/**
* Test quiz_send_confirmation function.
*/
public function test_quiz_send_confirmation() {
global $CFG, $DB;

$this->resetAfterTest();
$this->setAdminUser();
$this->preventResetByRollback();

$course = $this->getDataGenerator()->create_course();
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(['course' => $course->id]);
$cm = get_coursemodule_from_instance('quiz', $quiz->id);

$recipient = $this->getDataGenerator()->create_user(['email' => 'student@example.com']);

// Allow recipent to receive email confirm submission.
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
assign_capability('mod/quiz:emailconfirmsubmission', CAP_ALLOW, $studentrole->id,
context_course::instance($course->id), true);
$this->getDataGenerator()->enrol_user($recipient->id, $course->id, $studentrole->id, 'manual');

$timenow = time();
$data = new stdClass();
// Course info.
$data->courseid = $course->id;
$data->coursename = $course->fullname;
// Quiz info.
$data->quizname = $quiz->name;
$data->quizurl = $CFG->wwwroot . '/mod/quiz/view.php?id=' . $cm->id;
$data->quizid = $quiz->id;
$data->quizcmid = $quiz->cmid;
$data->attemptid = 1;
$data->submissiontime = userdate($timenow);

$sink = $this->redirectEmails();
quiz_send_confirmation($recipient, $data, true);
$messages = $sink->get_messages();
$message = reset($messages);
$this->assertStringContainsString("Thank you for submitting your answers" ,
quoted_printable_decode($message->body));
$sink->close();

$sink = $this->redirectEmails();
quiz_send_confirmation($recipient, $data, false);
$messages = $sink->get_messages();
$message = reset($messages);
$this->assertStringContainsString("Your answers were submitted automatically" ,
quoted_printable_decode($message->body));
$sink->close();
}
}

0 comments on commit dd6fd52

Please sign in to comment.