See Release Notes
Long Term Support Release
Differences Between: [Versions 401 and 402] [Versions 401 and 403]
1 <?php 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 17 namespace mod_quiz\task; 18 19 defined('MOODLE_INTERNAL') || die(); 20 21 use context_course; 22 use core_user; 23 use moodle_recordset; 24 use question_display_options; 25 use mod_quiz_display_options; 26 use quiz_attempt; 27 28 require_once($CFG->dirroot . '/mod/quiz/locallib.php'); 29 30 /** 31 * Cron Quiz Notify Attempts Graded Task. 32 * 33 * @package mod_quiz 34 * @copyright 2021 The Open University 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 * 37 */ 38 class quiz_notify_attempt_manual_grading_completed extends \core\task\scheduled_task { 39 /** 40 * @var int|null For using in unit testing only. Override the time we consider as now. 41 */ 42 protected $forcedtime = null; 43 44 /** 45 * Get name of schedule task. 46 * 47 * @return string 48 */ 49 public function get_name(): string { 50 return get_string('notifyattemptsgradedtask', 'mod_quiz'); 51 } 52 53 /** 54 * To let this class be unit tested, we wrap all accesses to the current time in this method. 55 * 56 * @return int The current time. 57 */ 58 protected function get_time(): int { 59 if (PHPUNIT_TEST && $this->forcedtime !== null) { 60 return $this->forcedtime; 61 } 62 63 return time(); 64 } 65 66 /** 67 * For testing only, pretend the current time is different. 68 * 69 * @param int $time The time to set as the current time. 70 */ 71 public function set_time_for_testing(int $time): void { 72 if (!PHPUNIT_TEST) { 73 throw new \coding_exception('set_time_for_testing should only be used in unit tests.'); 74 } 75 $this->forcedtime = $time; 76 } 77 78 /** 79 * Execute sending notification for manual graded attempts. 80 */ 81 public function execute() { 82 global $DB; 83 84 mtrace('Looking for quiz attempts which may need a graded notification sent...'); 85 86 $attempts = $this->get_list_of_attempts(); 87 $course = null; 88 $quiz = null; 89 $cm = null; 90 91 foreach ($attempts as $attempt) { 92 mtrace('Checking attempt ' . $attempt->id . ' at quiz ' . $attempt->quiz . '.'); 93 94 if (!$quiz || $attempt->quiz != $quiz->id) { 95 $quiz = $DB->get_record('quiz', ['id' => $attempt->quiz], '*', MUST_EXIST); 96 $cm = get_coursemodule_from_instance('quiz', $attempt->quiz); 97 } 98 99 if (!$course || $course->id != $quiz->course) { 100 $course = $DB->get_record('course', ['id' => $quiz->course], '*', MUST_EXIST); 101 $coursecontext = context_course::instance($quiz->course); 102 } 103 104 $quiz = quiz_update_effective_access($quiz, $attempt->userid); 105 $attemptobj = new quiz_attempt($attempt, $quiz, $cm, $course, false); 106 $options = mod_quiz_display_options::make_from_quiz($quiz, quiz_attempt_state($quiz, $attempt)); 107 108 if ($options->manualcomment == question_display_options::HIDDEN) { 109 // User cannot currently see the feedback, so don't message them. 110 // However, this may change in future, so leave them on the list. 111 continue; 112 } 113 114 if (!has_capability('mod/quiz:emailnotifyattemptgraded', $coursecontext, $attempt->userid, false)) { 115 // User not eligible to get a notification. Mark them done while doing nothing. 116 $DB->set_field('quiz_attempts', 'gradednotificationsenttime', $attempt->timefinish, ['id' => $attempt->id]); 117 continue; 118 } 119 120 // OK, send notification. 121 mtrace('Sending email to user ' . $attempt->userid . '...'); 122 $ok = quiz_send_notify_manual_graded_message($attemptobj, core_user::get_user($attempt->userid)); 123 if ($ok) { 124 mtrace('Send email successfully!'); 125 $attempt->gradednotificationsenttime = $this->get_time(); 126 $DB->set_field('quiz_attempts', 'gradednotificationsenttime', $attempt->gradednotificationsenttime, 127 ['id' => $attempt->id]); 128 $attemptobj->fire_attempt_manual_grading_completed_event(); 129 } 130 } 131 132 $attempts->close(); 133 } 134 135 /** 136 * Get a number of records as an array of quiz_attempts using a SQL statement. 137 * 138 * @return moodle_recordset Of quiz_attempts that need to be processed. 139 */ 140 public function get_list_of_attempts(): moodle_recordset { 141 global $DB; 142 143 $delaytime = $this->get_time() - get_config('quiz', 'notifyattemptgradeddelay'); 144 145 $sql = "SELECT qa.* 146 FROM {quiz_attempts} qa 147 JOIN {quiz} quiz ON quiz.id = qa.quiz 148 WHERE qa.state = 'finished' 149 AND qa.gradednotificationsenttime IS NULL 150 AND qa.sumgrades IS NOT NULL 151 AND qa.timemodified < :delaytime 152 ORDER BY quiz.course, qa.quiz"; 153 154 return $DB->get_recordset_sql($sql, ['delaytime' => $delaytime]); 155 } 156 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body