Completed
Push — master ( fcbece...7621e5 )
by René
26s queued 12s
created

MailService::generateInvitation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 33
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 2 Features 0
Metric Value
eloc 25
c 2
b 2
f 0
dl 0
loc 33
ccs 0
cts 27
cp 0
rs 9.52
cc 2
nc 2
nop 3
crap 6
1
<?php
2
/**
3
 * @copyright Copyright (c) 2017 Vinzenz Rosenkranz <[email protected]>
4
 *
5
 * @author René Gieling <[email protected]>
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 *  This program is free software: you can redistribute it and/or modify
10
 *  it under the terms of the GNU Affero General Public License as
11
 *  published by the Free Software Foundation, either version 3 of the
12
 *  License, or (at your option) any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU Affero General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU Affero General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
namespace OCA\Polls\Service;
25
26
use OCP\IUser;
27
use OCP\IUserManager;
28
use OCP\IGroupManager;
29
use OCP\IConfig;
30
use OCP\IURLGenerator;
31
use OCP\IL10N;
32
use OCP\L10N\IFactory;
33
use OCP\Mail\IMailer;
34
use OCP\Mail\IEMailTemplate;
35
36
use OCA\Polls\Db\SubscriptionMapper;
37
use OCA\Polls\Db\PollMapper;
38
use OCA\Polls\Db\ShareMapper;
39
use OCA\Polls\Db\LogMapper;
40
use OCA\Polls\Db\Log;
41
use OCA\Polls\Model\UserGroupClass;
42
use OCA\Polls\Model\Email;
43
use OCA\Polls\Model\User;
44
45
class MailService {
46
47
	/** @var IUserManager */
48
	private $userManager;
49
50
	/** @var IGroupManager */
51
	private $groupManager;
52
53
	/** @var IConfig */
54
	private $config;
55
56
	/** @var IURLGenerator */
57
	private $urlGenerator;
58
59
	/** @var IL10N */
60
	private $trans;
61
62
	/** @var IFactory */
63
	private $transFactory;
64
65
	/** @var IMailer */
66
	private $mailer;
67
68
	/** @var SubscriptionMapper */
69
	private $subscriptionMapper;
70
71
	/** @var ShareMapper */
72
	private $shareMapper;
73
74
	/** @var PollMapper */
75
	private $pollMapper;
76
77
	/** @var LogMapper */
78
	private $logMapper;
79
80
	/**
81
	 * MailService constructor.
82
	 * @param IUserManager $userManager
83
	 * @param IGroupManager $groupManager
84
	 * @param IConfig $config
85
	 * @param IURLGenerator $urlGenerator
86
	 * @param IL10N $trans
87
	 * @param IFactory $transFactory
88
	 * @param IMailer $mailer
89
	 * @param SubscriptionMapper $subscriptionMapper
90
	 * @param ShareMapper $shareMapper
91
	 * @param PollMapper $pollMapper
92
	 * @param LogMapper $logMapper
93
	 */
94
95
	public function __construct(
96
		IUserManager $userManager,
97
		IGroupManager $groupManager,
98
		IConfig $config,
99
		IURLGenerator $urlGenerator,
100
		IL10N $trans,
101
		IFactory $transFactory,
102
		IMailer $mailer,
103
		ShareMapper $shareMapper,
104
		SubscriptionMapper $subscriptionMapper,
105
		PollMapper $pollMapper,
106
		LogMapper $logMapper
107
	) {
108
		$this->config = $config;
109
		$this->userManager = $userManager;
110
		$this->groupManager = $groupManager;
111
		$this->urlGenerator = $urlGenerator;
112
		$this->trans = $trans;
113
		$this->transFactory = $transFactory;
114
		$this->mailer = $mailer;
115
		$this->shareMapper = $shareMapper;
116
		$this->subscriptionMapper = $subscriptionMapper;
117
		$this->pollMapper = $pollMapper;
118
		$this->logMapper = $logMapper;
119
	}
120
121
122
	/**
123
	 * sendMail - Send eMail and evaluate recipient's mail address
124
	 * and displayname if $userId is a site user
125
	 * @param IEmailTemplate $emailTemplate
126
	 * @param String $userId
127
	 * @param String $emailAddress, ignored, when $userId is set
128
	 * @param String $displayName, ignored, when $userId is set
129
	 * @return String
130
	 */
131
132
	private function sendMail($emailTemplate, $emailAddress, $displayName) {
133
		if (!$emailAddress || !filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
134
			throw new \Exception('Invalid email address (' . $emailAddress . ')');
135
		}
136
137
		try {
138
			$message = $this->mailer->createMessage();
139
			$message->setTo([$emailAddress => $displayName]);
140
			$message->useTemplate($emailTemplate);
141
			$this->mailer->send($message);
142
143
			return null;
144
		} catch (\Exception $e) {
145
			\OC::$server->getLogger()->logException($e->getMessage(), ['app' => 'polls']);
146
			throw $e;
147
		}
148
	}
149
150
	/**
151
	 * @param integer $pollId
152
	 * @param string $userId
153
	 * @return string
154
	 */
155
	public function resolveEmailAddress($pollId, $userId) {
156
		if ($this->userManager->get($userId) instanceof IUser) {
157
			return \OC::$server->getConfig()->getUserValue($userId, 'settings', 'email');
158
		}
159
160
		// if $userId is no site user, eval via shares
161
		try {
162
			$share = $this->shareMapper->findByPollAndUser($pollId, $userId);
163
			if ($share->getEmailAddress()) {
164
				return $share->getEmailAddress();
165
			}
166
		} catch (\Exception $e) {
167
			// catch silently
168
		}
169
		return $userId;
170
	}
171
172
	/**
173
	 * @param string $token
174
	 */
175
	public function sendInvitation($token) {
176
		$share = $this->shareMapper->findByToken($token);
177
		$poll = $this->pollMapper->find($share->getPollId());
178
		$sentMails = [];
179
		$abortedMails = [];
180
181
		foreach ($share->getMembers() as $recipient) {
182
			//skip poll owner
183
			if ($recipient->getId() === $poll->getOwner()) {
184
				continue;
185
			}
186
187
			$emailTemplate = $this->generateInvitation($recipient, $poll, $share->getURL());
188
189
			try {
190
				$this->sendMail(
191
					$emailTemplate,
192
					$recipient->getEmailAddress(),
193
					$recipient->getDisplayName()
194
				);
195
				$share->setInvitationSent(time());
196
				$this->shareMapper->update($share);
197
				$sentMails[] = $recipient->getId();
198
			} catch (\Exception $e) {
199
				$abortedMails[] = $recipient->getId();
200
				\OC::$server->getLogger()->alert('Error sending Mail to ' . json_encode($recipient));
201
			}
202
		}
203
		return ['sentMails' => $sentMails, 'abortedMails' => $abortedMails];
204
	}
205
206
	public function sendNotifications() {
207
		$subscriptions = [];
208
		$log = $this->logMapper->findUnprocessedPolls();
209
210
		foreach ($log as $logItem) {
211
			$subscriptions = array_merge($subscriptions, $this->subscriptionMapper->findAllByPoll($logItem->getPollId()));
212
		}
213
214
		$log = $this->logMapper->findUnprocessed();
215
216
		foreach ($subscriptions as $subscription) {
217
			$poll = $this->pollMapper->find($subscription->getPollId());
218
219
			if ($this->userManager->get($subscription->getUserId()) instanceof IUser) {
220
				$recipient = new User($subscription->getUserId());
221
				$url = $this->urlGenerator->linkToRouteAbsolute(
222
					'polls.page.vote',
223
					['id' => $subscription->getPollId()]
224
				);
225
			} else {
226
				try {
227
					$share = $this->shareMapper->findByPollAndUser($subscription->getPollId(), $subscription->getUserId());
228
					$recipient = $share->getUserObject();
229
					$url = $share->getURL();
230
				} catch (\Exception $e) {
231
					continue;
232
				}
233
			}
234
235
			$emailTemplate = $this->generateNotification($recipient, $poll, $url, $log);
236
237
			try {
238
				$this->sendMail(
239
					$emailTemplate,
240
					$recipient->getEmailAddress(),
241
					$recipient->getDisplayName()
242
				);
243
			} catch (\Exception $e) {
244
				\OC::$server->getLogger()->alert('Error sending Mail to ' . $recipient->getId());
245
			}
246
		}
247
	}
248
249
	/**
250
	 * getLogString
251
	 * @param Log $logItem
252
	 * @param string $displayName
253
	 * @return string
254
	 */
255
256
	private function getLogString($logItem, $displayName) {
257
		if ($logItem->getMessage()) {
258
			return $logItem->getMessage();
259
		}
260
261
		switch ($logItem->getMessageId()) {
262
			case Log::MSG_ID_SETVOTE:
263
				return $this->trans->t('- %s voted.', [$displayName]);
264
			case Log::MSG_ID_UPDATEPOLL:
265
				return $this->trans->t('- Updated poll configuration. Please check your votes.');
266
			case Log::MSG_ID_DELETEPOLL:
267
				return $this->trans->t('- The poll got deleted.');
268
			case Log::MSG_ID_RESTOREPOLL:
269
				return $this->trans->t('- The poll got restored.');
270
			case Log::MSG_ID_EXPIREPOLL:
271
				return $this->trans->t('- The poll was closed.');
272
			case Log::MSG_ID_ADDOPTION:
273
				return $this->trans->t('- A vote option was added.');
274
			case Log::MSG_ID_DELETEOPTION:
275
				return $this->trans->t('- A vote option was removed.');
276
			default:
277
				return $logItem->getMessageId() . " (" . $displayName . ")";
278
		}
279
	}
280
281
	/**
282
	 * generateNotification
283
	 * @param UserGroupClass $recipient
284
	 * @param Poll $poll
285
	 * @return Object $emailTemplate
286
	 */
287
288
	private function generateNotification($recipient, $poll, $url, $log) {
289
		if ($recipient->getLanguage()) {
290
			$this->trans = $this->transFactory->get('polls', $recipient->getLanguage());
291
		} else {
292
			$this->trans = $this->transFactory->get('polls', $poll->getOwnerUserObject()->getLanguage());
293
		}
294
		$emailTemplate = $this->mailer->createEMailTemplate('polls.Notification', [
295
			'title' => $poll->getTitle(),
296
			'link' => $url
297
		]);
298
299
		$emailTemplate->setSubject($this->trans->t('Polls App - New Activity'));
300
		$emailTemplate->addHeader();
301
		$emailTemplate->addHeading($this->trans->t('Polls App - New Activity'), false);
302
		$emailTemplate->addBodyText(str_replace(
303
			['{title}'],
304
			[$poll->getTitle()],
305
			$this->trans->t('"{title}" had recent activity: ')
306
		));
307
		foreach ($log as $logItem) {
308
			if ($logItem->getPollId() === $poll->getId()) {
309
				if ($poll->getAnonymous() || $poll->getShowResults() !== "always") {
310
					$displayName = $this->trans->t('A user');
311
				} elseif ($this->userManager->get($logItem->getUserId()) instanceof IUser) {
312
					$actor = new User($logItem->getUserId());
313
					$displayName = $actor->getDisplayName();
314
				} else {
315
					try {
316
						$share = $this->shareMapper->findByPollAndUser($poll->getId(), $logItem->getUserId());
317
						$displayName = $share->getUserObject()->getDisplayName();
318
					} catch (\Exception $e) {
319
						$displayName = $logItem->getUserId();
320
					}
321
				}
322
323
				$emailTemplate->addBodyText($this->getLogString($logItem, $displayName));
324
			}
325
326
			$logItem->setProcessed(time());
327
			$this->logMapper->update($logItem);
328
		}
329
330
		$emailTemplate->addBodyButton(
331
			htmlspecialchars($this->trans->t('Go to poll')),
332
			$url,
333
			/** @scrutinizer ignore-type */ false
334
		);
335
		$emailTemplate->addFooter($this->trans->t('This email is sent to you, because you subscribed to notifications of this poll. To opt out, visit the poll and remove your subscription.'));
336
337
		return $emailTemplate;
338
	}
339
340
	/**
341
	 * generateInvitation
342
	 * @param UserGroupClass $recipient
343
	 * @param Poll $poll
344
	 * @return Object $emailTemplate
345
	 */
346
347
	private function generateInvitation($recipient, $poll, $url) {
348
		$owner = $poll->getOwnerUserObject();
349
		if ($recipient->getLanguage()) {
350
			$this->trans = $this->transFactory->get('polls', $recipient->getLanguage());
351
		} else {
352
			$this->trans = $this->transFactory->get('polls', $owner->getLanguage());
353
		}
354
355
		$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
356
			'owner' => $owner->getDisplayName(),
357
			'title' => $poll->getTitle(),
358
			'link' => $url
359
		]);
360
361
		$emailTemplate->setSubject($this->trans->t('Poll invitation "%s"', $poll->getTitle()));
362
		$emailTemplate->addHeader();
363
		$emailTemplate->addHeading($this->trans->t('Poll invitation "%s"', $poll->getTitle()), false);
364
		$emailTemplate->addBodyText(str_replace(
365
				['{owner}', '{title}'],
366
				[$owner->getDisplayName(), $poll->getTitle()],
367
				$this->trans->t('{owner} invited you to take part in the poll "{title}"')
368
			));
369
		$emailTemplate->addBodyText($poll->getDescription());
370
		$emailTemplate->addBodyButton(
371
				htmlspecialchars($this->trans->t('Go to poll')),
372
				$url
373
			);
374
		$emailTemplate->addBodyText($this->trans->t('This link gives you personal access to the poll named above. Press the button above or copy the following link and add it in your browser\'s location bar: '));
375
		$emailTemplate->addBodyText($url);
376
		$emailTemplate->addBodyText($this->trans->t('Do not share this link with other people, because it is connected to your votes.'));
377
		$emailTemplate->addFooter($this->trans->t('This email is sent to you, because you are invited to vote in this poll by the poll owner. At least your name or your email address is recorded in this poll. If you want to get removed from this poll, contact the site administrator or the initiator of this poll, where the mail is sent from.'));
378
379
		return $emailTemplate;
380
	}
381
}
382