Merge pull request #5951 from WoltLab/upload-form-field-v2
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / worker / MailWorker.class.php
1 <?php
2
3 namespace wcf\system\worker;
4
5 use wcf\data\user\User;
6 use wcf\system\background\BackgroundQueueHandler;
7 use wcf\system\clipboard\ClipboardHandler;
8 use wcf\system\database\util\PreparedStatementConditionBuilder;
9 use wcf\system\email\Email;
10 use wcf\system\email\Mailbox;
11 use wcf\system\email\mime\MimePartFacade;
12 use wcf\system\email\mime\RecipientAwareTextMimePart;
13 use wcf\system\email\UserMailbox;
14 use wcf\system\exception\SystemException;
15 use wcf\system\request\LinkHandler;
16 use wcf\system\WCF;
17
18 /**
19 * Worker implementation for sending mails.
20 *
21 * @author Alexander Ebert
22 * @copyright 2001-2019 WoltLab GmbH
23 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
24 */
25 class MailWorker extends AbstractWorker
26 {
27 /**
28 * condition builder object
29 * @var PreparedStatementConditionBuilder
30 */
31 protected $conditions;
32
33 /**
34 * @inheritDoc
35 */
36 protected $limit = 50;
37
38 /**
39 * mail data
40 * @var array
41 */
42 protected $mailData;
43
44 /**
45 * @inheritDoc
46 */
47 public function validate()
48 {
49 WCF::getSession()->checkPermissions(['admin.user.canMailUser']);
50
51 if (!isset($this->parameters['mailID'])) {
52 throw new SystemException("mailID missing");
53 }
54
55 $userMailData = WCF::getSession()->getVar('userMailData');
56 if (!isset($userMailData[$this->parameters['mailID']])) {
57 throw new SystemException("mailID '" . $this->parameters['mailID'] . "' is invalid");
58 }
59
60 $this->mailData = $userMailData[$this->parameters['mailID']];
61 if (!isset($this->mailData['message-id'])) {
62 $this->mailData['message-id'] = \sprintf(
63 'com.woltlab.wcf.mailWorker/%d/%s',
64 TIME_NOW,
65 \bin2hex(\random_bytes(8))
66 );
67 $userMailData[$this->parameters['mailID']] = $this->mailData;
68 WCF::getSession()->register('userMailData', $userMailData);
69 }
70 }
71
72 /**
73 * @inheritDoc
74 */
75 public function countObjects()
76 {
77 $this->conditions = new PreparedStatementConditionBuilder();
78 if ($this->mailData['action'] == '') {
79 $this->conditions->add("user.userID IN (?)", [$this->mailData['userIDs']]);
80 } else {
81 $this->conditions->add("user.emailConfirmed IS NULL");
82 $this->conditions->add("user.banned = ?", [0]);
83
84 if ($this->mailData['action'] == 'group') {
85 $this->conditions->add(
86 "user.userID IN (
87 SELECT userID
88 FROM wcf" . WCF_N . "_user_to_group
89 WHERE groupID IN (?)
90 )",
91 [$this->mailData['groupIDs']]
92 );
93 }
94 }
95
96 $sql = "SELECT COUNT(*)
97 FROM wcf" . WCF_N . "_user user
98 " . $this->conditions;
99 $statement = WCF::getDB()->prepareStatement($sql);
100 $statement->execute($this->conditions->getParameters());
101
102 $this->count = $statement->fetchSingleColumn();
103 }
104
105 /**
106 * @inheritDoc
107 */
108 public function getProgress()
109 {
110 $progress = parent::getProgress();
111
112 if ($progress == 100) {
113 // clear markings
114 $typeID = ClipboardHandler::getInstance()->getObjectTypeID('com.woltlab.wcf.user');
115 ClipboardHandler::getInstance()->removeItems($typeID);
116
117 // clear session
118 $userMailData = WCF::getSession()->getVar('userMailData');
119 unset($userMailData[$this->parameters['mailID']]);
120 WCF::getSession()->register('userMailData', $userMailData);
121 }
122
123 return $progress;
124 }
125
126 /**
127 * @inheritDoc
128 */
129 public function execute()
130 {
131 $email = new Email();
132 $email->setMessageID($this->mailData['message-id']);
133 $email->setSubject($this->mailData['subject']);
134 $from = new Mailbox(
135 $this->mailData['from'],
136 (!empty($this->mailData['fromName']) ? $this->mailData['fromName'] : null)
137 );
138 $email->setSender($from);
139 $email->setReplyTo($from);
140 $variables = [
141 'text' => $this->mailData['text'],
142 'enableHTML' => $this->mailData['enableHTML'] ? true : false,
143 ];
144 if ($this->mailData['enableHTML']) {
145 $email->setBody(new RecipientAwareTextMimePart('text/html', 'email_mailWorker', 'wcf', $variables));
146 } else {
147 $email->setBody(new MimePartFacade([
148 new RecipientAwareTextMimePart('text/html', 'email_mailWorker', 'wcf', $variables),
149 new RecipientAwareTextMimePart('text/plain', 'email_mailWorker', 'wcf', $variables),
150 ]));
151 }
152
153 // get users
154 $sql = "SELECT user_option.*, user.*
155 FROM wcf" . WCF_N . "_user user
156 LEFT JOIN wcf" . WCF_N . "_user_option_value user_option
157 ON user_option.userID = user.userID
158 " . $this->conditions . "
159 ORDER BY user.userID";
160 $statement = WCF::getDB()->prepareStatement($sql, $this->limit, $this->limit * $this->loopCount);
161 $statement->execute($this->conditions->getParameters());
162 while ($row = $statement->fetchArray()) {
163 $user = new User(null, $row);
164 $adminCanMail = $user->adminCanMail;
165 if ($adminCanMail === null || $adminCanMail) {
166 $this->sendMail($email, $user);
167 }
168 }
169 }
170
171 /**
172 * Sends the given blueprint (Email without recipients) to the given user.
173 *
174 * @param Email $blueprint
175 * @param User $user
176 */
177 protected function sendMail(Email $blueprint, User $user)
178 {
179 $email = clone $blueprint;
180 $email->addRecipient(new UserMailbox($user));
181 $jobs = $email->getJobs();
182 foreach ($jobs as $job) {
183 BackgroundQueueHandler::getInstance()->performJob($job);
184 }
185 }
186
187 /**
188 * @inheritDoc
189 */
190 public function getProceedURL()
191 {
192 return LinkHandler::getInstance()->getLink('UserList');
193 }
194 }