See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401] [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 /** 18 * Contains the class responsible for sending emails as a digest. 19 * 20 * @package message_email 21 * @copyright 2019 Mark Nelson <markn@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 namespace message_email\task; 25 26 use core\task\scheduled_task; 27 use moodle_recordset; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 /** 32 * Class responsible for sending emails as a digest. 33 * 34 * @package message_email 35 * @copyright 2019 Mark Nelson <markn@moodle.com> 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class send_email_task extends scheduled_task { 39 40 /** 41 * @var int $maxid This is the maximum id of the message in 'message_email_messages'. 42 * We use this so we know what records to process, as more records may be added 43 * while this task runs. 44 */ 45 private $maxid; 46 47 /** 48 * Get a descriptive name for this task (shown to admins). 49 * 50 * @return string 51 */ 52 public function get_name() { 53 return get_string('tasksendemail', 'message_email'); 54 } 55 56 /** 57 * Send out emails. 58 */ 59 public function execute() { 60 global $DB, $PAGE, $SITE; 61 62 // Get the maximum id we are going to use. 63 // We use this as records may be added to the table while this task runs. 64 $this->maxid = $DB->get_field_sql("SELECT MAX(id) FROM {message_email_messages}"); 65 66 // We are going to send these emails from 'noreplyaddress'. 67 $noreplyuser = \core_user::get_noreply_user(); 68 69 // The renderers used for sending emails. 70 $htmlrenderer = $PAGE->get_renderer('message_email', 'email', 'htmlemail'); 71 $textrenderer = $PAGE->get_renderer('message_email', 'email', 'textemail'); 72 73 // Keep track of which emails failed to send. 74 $users = $this->get_unique_users(); 75 foreach ($users as $user) { 76 cron_setup_user($user); 77 78 $hascontent = false; 79 $renderable = new \message_email\output\email_digest($user); 80 $conversations = $this->get_conversations_for_user($user->id); 81 foreach ($conversations as $conversation) { 82 $renderable->add_conversation($conversation); 83 $messages = $this->get_users_messages_for_conversation($conversation->id, $user->id); 84 if ($messages->valid()) { 85 $hascontent = true; 86 foreach ($messages as $message) { 87 $renderable->add_message($message); 88 } 89 } 90 $messages->close(); 91 } 92 $conversations->close(); 93 if ($hascontent) { 94 $subject = get_string('messagedigestemailsubject', 'message_email', format_string($SITE->fullname)); 95 $message = $textrenderer->render($renderable); 96 $messagehtml = $htmlrenderer->render($renderable); 97 if (email_to_user($user, $noreplyuser, $subject, $message, $messagehtml)) { 98 $DB->delete_records_select('message_email_messages', 'useridto = ? AND id <= ?', [$user->id, $this->maxid]); 99 } 100 } 101 } 102 cron_setup_user(); 103 $users->close(); 104 } 105 106 /** 107 * Returns an array of users in the given conversation. 108 * 109 * @return moodle_recordset A moodle_recordset instance. 110 */ 111 private function get_unique_users() : moodle_recordset { 112 global $DB; 113 114 $subsql = 'SELECT DISTINCT(useridto) as id 115 FROM {message_email_messages} 116 WHERE id <= ?'; 117 118 $sql = "SELECT * 119 FROM {user} u 120 WHERE id IN ($subsql)"; 121 122 return $DB->get_recordset_sql($sql, [$this->maxid]); 123 } 124 125 /** 126 * Returns an array of unique conversations that require processing. 127 * 128 * @param int $userid The ID of the user we are sending a digest to. 129 * @return moodle_recordset A moodle_recordset instance. 130 */ 131 private function get_conversations_for_user(int $userid) : moodle_recordset { 132 global $DB; 133 134 // We shouldn't be joining directly on the group table as group 135 // conversations may (in the future) be something created that 136 // isn't related to an actual group in a course. However, for 137 // now this will have to do before 3.7 code freeze. 138 // See related MDL-63814. 139 $sql = "SELECT DISTINCT mc.id, mc.name, c.id as courseid, c.fullname as coursename, g.id as groupid, 140 g.picture 141 FROM {message_conversations} mc 142 JOIN {groups} g 143 ON mc.itemid = g.id 144 JOIN {course} c 145 ON g.courseid = c.id 146 JOIN {message_email_messages} mem 147 ON mem.conversationid = mc.id 148 WHERE mem.useridto = ? 149 AND mem.id <= ?"; 150 151 return $DB->get_recordset_sql($sql, [$userid, $this->maxid]); 152 } 153 154 /** 155 * Returns the messages to send to a user for a given conversation 156 * 157 * @param int $conversationid 158 * @param int $userid 159 * @return moodle_recordset A moodle_recordset instance. 160 */ 161 protected function get_users_messages_for_conversation(int $conversationid, int $userid) : moodle_recordset { 162 global $DB; 163 164 $userfieldsapi = \core_user\fields::for_userpic(); 165 $usernamefields = $userfieldsapi->get_sql('u', false, '', '', false)->selects; 166 $sql = "SELECT $usernamefields, m.* 167 FROM {messages} m 168 JOIN {user} u 169 ON u.id = m.useridfrom 170 JOIN {message_email_messages} mem 171 ON mem.messageid = m.id 172 WHERE mem.useridto = ? 173 AND mem.conversationid = ? 174 AND mem.id <= ?"; 175 176 return $DB->get_recordset_sql($sql, [$userid, $conversationid, $this->maxid]); 177 } 178 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body