MDL-64017 message_email: fixed incorrect unread count
[moodle.git] / message / output / email / classes / task / send_email_task.php
CommitLineData
168d782f
MN
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 */
24namespace message_email\task;
25
26use core\task\scheduled_task;
27use moodle_recordset;
28
29defined('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 */
38class 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;
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 $hascontent = false;
77 $renderable = new \message_email\output\email_digest($user);
78 $conversations = $this->get_conversations_for_user($user->id);
79 foreach ($conversations as $conversation) {
80 $renderable->add_conversation($conversation);
81 $messages = $this->get_users_messages_for_conversation($conversation->id, $user->id);
82 if ($messages->valid()) {
83 $hascontent = true;
84 foreach ($messages as $message) {
85 $renderable->add_message($message);
86 }
87 }
88 $messages->close();
89 }
90 $conversations->close();
91 if ($hascontent) {
92 $subject = get_string('emaildigestsubject', 'message_email');
93 $message = $textrenderer->render($renderable);
94 $messagehtml = $htmlrenderer->render($renderable);
95 if (email_to_user($user, $noreplyuser, $subject, $message, $messagehtml)) {
96 $DB->delete_records_select('message_email_messages', 'useridto = ? AND id <= ?', [$user->id, $this->maxid]);
97 }
98 }
99 }
100 $users->close();
101 }
102
103 /**
104 * Returns an array of users in the given conversation.
105 *
106 * @return moodle_recordset A moodle_recordset instance.
107 */
108 private function get_unique_users() : moodle_recordset {
109 global $DB;
110
111 $subsql = 'SELECT DISTINCT(useridto) as id
112 FROM {message_email_messages}
113 WHERE id <= ?';
114
115 $sql = "SELECT *
116 FROM {user} u
117 WHERE id IN ($subsql)";
118
119 return $DB->get_recordset_sql($sql, [$this->maxid]);
120 }
121
122 /**
123 * Returns an array of unique conversations that require processing.
124 *
125 * @param int $userid The ID of the user we are sending a digest to.
126 * @return moodle_recordset A moodle_recordset instance.
127 */
128 private function get_conversations_for_user(int $userid) : moodle_recordset {
129 global $DB;
130
131 // We shouldn't be joining directly on the group table as group
132 // conversations may (in the future) be something created that
133 // isn't related to an actual group in a course. However, for
134 // now this will have to do before 3.7 code freeze.
135 // See related MDL-63814.
c0153364
MN
136 $sql = "SELECT DISTINCT mc.id, mc.name, c.id as courseid, c.fullname as coursename, g.id as groupid,
137 g.picture, g.hidepicture
168d782f
MN
138 FROM {message_conversations} mc
139 JOIN {groups} g
140 ON mc.itemid = g.id
141 JOIN {course} c
142 ON g.courseid = c.id
143 JOIN {message_email_messages} mem
144 ON mem.conversationid = mc.id
145 WHERE mem.useridto = ?
146 AND mem.id <= ?";
147
148 return $DB->get_recordset_sql($sql, [$userid, $this->maxid]);
149 }
150
151 /**
152 * Returns the messages to send to a user for a given conversation
153 *
154 * @param int $conversationid
155 * @param int $userid
156 * @return moodle_recordset A moodle_recordset instance.
157 */
158 protected function get_users_messages_for_conversation(int $conversationid, int $userid) : moodle_recordset {
159 global $DB;
160
161 $usernamefields = \user_picture::fields('u');
162 $sql = "SELECT $usernamefields, m.*
163 FROM {messages} m
164 JOIN {user} u
165 ON u.id = m.useridfrom
166 JOIN {message_email_messages} mem
167 ON mem.messageid = m.id
168 WHERE mem.useridto = ?
169 AND mem.conversationid = ?
170 AND mem.id <= ?";
171
172 return $DB->get_recordset_sql($sql, [$userid, $conversationid, $this->maxid]);
173 }
174}