Passed
Push — master ( cf3e21...3c965b )
by René
05:47 queued 11s
created

MailService   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 383
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 9
Bugs 3 Features 1
Metric Value
wmc 39
eloc 220
c 9
b 3
f 1
dl 0
loc 383
ccs 0
cts 278
cp 0
rs 9.28

5 Methods

Rating   Name   Duplication   Size   Complexity  
A sendMail() 0 22 6
A __construct() 0 26 1
C getRecipientsByShare() 0 95 11
A sendInvitationMail() 0 60 3
D sendNotifications() 0 118 18
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 Exception;
27
28
use OCP\IUser;
29
use OCP\IUserManager;
30
use OCP\IGroupManager;
31
use OCP\IConfig;
32
use OCP\IURLGenerator;
33
use OCP\IL10N;
34
use OCP\L10N\IFactory;
35
use OCP\Mail\IMailer;
36
use OCP\Mail\IEMailTemplate;
37
use OCP\ILogger;
38
39
use OCA\Polls\Db\SubscriptionMapper;
40
use OCA\Polls\Db\Subscription;
41
use OCA\Polls\Db\PollMapper;
42
use OCA\Polls\Db\Poll;
43
use OCA\Polls\Db\ShareMapper;
44
use OCA\Polls\Db\Share;
45
use OCA\Polls\Db\LogMapper;
46
47
class MailService {
48
49
	private $userManager;
50
	private $groupManager;
51
	private $config;
52
	private $urlGenerator;
53
	private $trans;
54
	private $transFactory;
55
	private $mailer;
56
	private $logger;
57
58
	private $shareMapper;
59
	private $subscriptionMapper;
60
	private $pollMapper;
61
	private $logMapper;
62
63
	/**
64
	 * MailService constructor.
65
	 * @param IUserManager $userManager
66
	 * @param IGroupManager $groupManager
67
	 * @param IConfig $config
68
	 * @param IURLGenerator $urlGenerator
69
	 * @param IL10N $trans
70
	 * @param IFactory $transFactory
71
	 * @param IMailer $mailer
72
	 * @param ILogger $logger
73
	 * @param SubscriptionMapper $subscriptionMapper
74
	 * @param ShareMapper $shareMapper
75
	 * @param PollMapper $pollMapper
76
	 * @param LogMapper $logMapper
77
	 */
78
79
	public function __construct(
80
		IUserManager $userManager,
81
		IGroupManager $groupManager,
82
		IConfig $config,
83
		IURLGenerator $urlGenerator,
84
		IL10N $trans,
85
		IFactory $transFactory,
86
		IMailer $mailer,
87
		ILogger $logger,
88
		ShareMapper $shareMapper,
89
		SubscriptionMapper $subscriptionMapper,
90
		PollMapper $pollMapper,
91
		LogMapper $logMapper
92
	) {
93
		$this->config = $config;
94
		$this->userManager = $userManager;
95
		$this->groupManager = $groupManager;
96
		$this->urlGenerator = $urlGenerator;
97
		$this->trans = $trans;
98
		$this->transFactory = $transFactory;
99
		$this->mailer = $mailer;
100
		$this->logger = $logger;
101
		$this->shareMapper = $shareMapper;
102
		$this->subscriptionMapper = $subscriptionMapper;
103
		$this->pollMapper = $pollMapper;
104
		$this->logMapper = $logMapper;
105
	}
106
107
108
	/**
109
	 * sendMail - Send eMail and evaluate recipient's mail address
110
	 * and displayname if $toUserId is a site user
111
	 * @param IEmailTemplate $emailTemplate
112
	 * @param String $toUserId
113
	 * @param String $toEmail
114
	 * @param String $toDisplayName
115
	 * @return String
116
	 */
117
118
	private function sendMail($emailTemplate, $toUserId = '', $toEmail = '', $toDisplayName = '') {
119
120
		if ($this->userManager->get($toUserId) instanceof IUser && !$toEmail) {
121
			$toEmail = \OC::$server->getConfig()->getUserValue($toUserId, 'settings', 'email');
122
			$toDisplayName = $this->userManager->get($toUserId)->getDisplayName();
123
		}
124
125
		if (!$toEmail || !filter_var($toEmail, FILTER_VALIDATE_EMAIL)) {
126
	   		throw new Exception('Invalid email address (' . $toEmail . ')');
127
		}
128
129
		try {
130
			$message = $this->mailer->createMessage();
131
			$message->setTo([$toEmail => $toDisplayName]);
132
			$message->useTemplate($emailTemplate);
133
			$this->mailer->send($message);
134
135
			return null;
136
137
		} catch (\Exception $e) {
138
			$this->logger->logException($e, ['app' => 'polls']);
139
			throw $e;
140
		}
141
142
	}
143
144
	/**
145
	 * @param Share $share
146
	 * @param String $defaultLang
147
	 * @param String $skipUser
148
	 * @return Array $recipients
149
	 */
150
	private function getRecipientsByShare($share, $defaultLang = 'en', $skipUser = null) {
151
		$recipients = [];
152
		$contactsManager = \OC::$server->getContactsManager();
153
154
		if ($share->getType() === 'user') {
155
156
			$recipients[] = array(
157
				'userId' => $share->getUserId(),
158
				'eMailAddress' => null,
159
				'displayName' => null,
160
				'language' => $this->config->getUserValue(
161
					$share->getUserId(),
162
					'core', 'lang'
163
				),
164
				'link' => $this->urlGenerator->getAbsoluteURL(
165
					$this->urlGenerator->linkToRoute(
166
						'polls.page.indexvote',
167
						array('id' => $share->getPollId())
168
					)
169
				)
170
			);
171
172
		} elseif ($share->getType() === 'email') {
173
			$recipients[] = array(
174
				'userId' => $share->getUserEmail(),
175
				'eMailAddress' => $share->getUserEmail(),
176
				'displayName' => $share->getUserEmail(),
177
				'language' => $defaultLang,
178
				'link' => $this->urlGenerator->getAbsoluteURL(
179
					$this->urlGenerator->linkToRoute(
180
						'polls.page.vote_publicpublic',
181
						array('token' => $share->getToken())
182
					)
183
				)
184
			);
185
186
		} elseif ($share->getType() === 'contact') {
187
			$contacts = $contactsManager->search($share->getUserId(), array('FN'));
188
			if (is_array($contacts)) {
189
				$contact = $contacts[0];
190
191
				$recipients[] = array(
192
					'userId' => $share->getUserId(),
193
					'eMailAddress' => $contact['EMAIL'][0],
194
					'displayName' => $contact['FN'],
195
					'language' => $defaultLang,
196
					'link' => $this->urlGenerator->getAbsoluteURL(
197
						$this->urlGenerator->linkToRoute(
198
							'polls.page.vote_publicpublic',
199
							array('token' => $share->getToken())
200
						)
201
					)
202
				);
203
			} else {
204
				return;
205
			}
206
207
		} elseif ($share->getType() === 'external' || $share->getType() === 'email') {
208
			$recipients[] = array(
209
				'userId' => $share->getUserId(),
210
				'eMailAddress' => $share->getUserEmail(),
211
				'displayName' => $share->getUserId(),
212
				'language' => $defaultLang,
213
				'link' => $this->urlGenerator->getAbsoluteURL(
214
					$this->urlGenerator->linkToRoute(
215
						'polls.page.vote_publicpublic',
216
						array('token' => $share->getToken())
217
					)
218
				)
219
			);
220
221
		} elseif ($share->getType() === 'group') {
222
223
			$groupMembers = array_keys($this->groupManager->displayNamesInGroup($share->getUserId()));
224
225
			foreach ($groupMembers as $member) {
226
				if ($skipUser === $member || !$this->userManager->get($member)->isEnabled() ) {
227
					continue;
228
				}
229
230
				$recipients[] = array(
231
					'userId' => $member,
232
					'eMailAddress' => null,
233
					'displayName' => null,
234
					'language' => $this->config->getUserValue($share->getUserId(), 'core', 'lang'),
235
					'link' => $this->urlGenerator->getAbsoluteURL(
236
						$this->urlGenerator->linkToRoute(
237
							'polls.page.indexvote', ['id' => $share->getPollId()]
238
						)
239
					)
240
				);
241
242
			}
243
		}
244
		return $recipients;
245
	}
246
247
	/**
248
	 * @param string $token
249
	 */
250
	public function sendInvitationMail($token) {
251
252
		$share = $this->shareMapper->findByToken($token);
253
		$poll = $this->pollMapper->find($share->getPollId());
254
		$owner = $this->userManager->get($poll->getOwner());
255
		$sentMails = [];
256
		$abortedMails = [];
257
258
		$recipients = $this->getRecipientsByShare(
259
			$this->shareMapper->findByToken($token),
260
			$this->config->getUserValue($poll->getOwner(), 'core', 'lang'),
261
			$poll->getOwner()
262
		);
263
264
		foreach ($recipients as $recipient) {
265
			$trans = $this->transFactory->get('polls', $recipient['language']);
266
267
268
			$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
269
				'owner' => $owner->getDisplayName(),
270
				'title' => $poll->getTitle(),
271
				'link' => $recipient['link']
272
			]);
273
274
			$emailTemplate->setSubject($trans->t('Poll invitation "%s"', $poll->getTitle()));
275
			$emailTemplate->addHeader();
276
			$emailTemplate->addHeading($trans->t('Poll invitation "%s"', $poll->getTitle()), false);
277
278
			$emailTemplate->addBodyText(str_replace(
279
				['{owner}', '{title}'],
280
				[$owner->getDisplayName(), $poll->getTitle()],
281
				$trans->t('{owner} invited you to take part in the poll "{title}"')
282
			));
283
284
			$emailTemplate->addBodyText($poll->getDescription());
285
286
			$emailTemplate->addBodyButton(
287
				htmlspecialchars($trans->t('Go to poll')),
288
				$recipient['link']
289
			);
290
291
			$emailTemplate->addBodyText($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: '));
292
			$emailTemplate->addBodyText($recipient['link']);
293
294
			$emailTemplate->addFooter($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.'));
295
296
			try {
297
				$this->sendMail(
298
					$emailTemplate,
299
					$recipient['userId'],
300
					$recipient['eMailAddress'],
301
					$recipient['displayName']
302
				);
303
				$sentMails[] = $recipient;
304
			} catch (Exception $e) {
305
				$abortedMails[] = $recipient;
306
				$this->logger->alert('Error sending Mail to ' . json_encode($recipient));
307
			}
308
		}
309
		return ['sentMails' => $sentMails, 'abortedMails' => $abortedMails];
310
	}
311
312
	public function sendNotifications() {
313
		$subscriptions = [];
314
		$log = $this->logMapper->findUnprocessedPolls();
315
316
		foreach ($log as $logItem) {
317
			$subscriptions = array_merge($subscriptions, $this->subscriptionMapper->findAllByPoll($logItem->getPollId()));
318
		}
319
320
		$log = $this->logMapper->findUnprocessed();
321
322
		foreach ($subscriptions as $subscription) {
323
324
			if ($this->userManager->get($subscription->getUserId()) instanceof IUser) {
325
				$lang = $this->config->getUserValue($subscription->getUserId(), 'core', 'lang');
326
			} else {
327
				continue;
328
			}
329
330
			$poll = $this->pollMapper->find($subscription->getPollId());
331
			$trans = $this->transFactory->get('polls', $lang);
332
333
			$url = $this->urlGenerator->getAbsoluteURL(
334
				$this->urlGenerator->linkToRoute(
335
					'polls.page.indexvote',
336
					array('id' => $subscription->getPollId())
337
				)
338
			);
339
340
			$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
341
				'title' => $poll->getTitle(),
342
				'link' => $url
343
			]);
344
			$emailTemplate->setSubject($trans->t('Polls App - New Activity'));
345
			$emailTemplate->addHeader();
346
			$emailTemplate->addHeading($trans->t('Polls App - New Activity'), false);
347
			$emailTemplate->addBodyText(str_replace(
348
				['{title}'],
349
				[$poll->getTitle()],
350
				$trans->t('"{title}" had recent activity: ')
351
			));
352
353
			foreach ($log as $logItem) {
354
				if ($logItem->getPollId() === $subscription->getPollId()) {
355
					if ($poll->getAnonymous() || $poll->getShowResults() !== "always") {
356
						$displayUser = "A user";
357
					} elseif ($this->userManager->get($logItem->getUserId()) instanceof IUser) {
358
						$displayUser = $this->userManager->get($logItem->getUserId())->getDisplayName();
359
					} else {
360
						$displayUser = $logItem->getUserId();
361
					}
362
363
					if ($logItem->getMessage()) {
364
						$emailTemplate->addBodyText($logItem->getMessage());
365
366
					} elseif ($logItem->getMessageId() === 'setVote') {
367
						$emailTemplate->addBodyText($trans->t(
368
							'- %s voted.',
369
							array($displayUser)
370
						));
371
372
					} elseif ($logItem->getMessageId() === 'updatePoll') {
373
						$emailTemplate->addBodyText($trans->t(
374
							'- %s updated the poll configuration. Please check your votes.',
375
							array($displayUser)
376
						));
377
378
					} elseif ($logItem->getMessageId() === 'deletePoll') {
379
						$emailTemplate->addBodyText($trans->t(
380
							'- %s deleted the poll.',
381
							array($displayUser)
382
						));
383
384
					} elseif ($logItem->getMessageId() === 'restorePoll') {
385
						$emailTemplate->addBodyText($trans->t(
386
							'- %s restored the poll.',
387
							array($displayUser)
388
						));
389
390
					} elseif ($logItem->getMessageId() === 'expirePoll') {
391
						$emailTemplate->addBodyText($trans->t(
392
							'- The poll expired.',
393
							array($displayUser)
394
						));
395
396
					} elseif ($logItem->getMessageId() === 'addOption') {
397
						$emailTemplate->addBodyText($trans->t(
398
							'- %s added a vote option.',
399
							array($displayUser)
400
						));
401
402
					} elseif ($logItem->getMessageId() === 'deleteOption') {
403
						$emailTemplate->addBodyText($trans->t(
404
							'- %s removed a vote option.',
405
							array($displayUser)
406
						));
407
408
					} else {
409
						$emailTemplate->addBodyText(
410
							$logItem->getMessageId() . " (" . $displayUser . ")"
411
						);
412
					}
413
				}
414
415
				$logItem->setProcessed(time());
416
				$this->logMapper->update($logItem);
417
			}
418
419
			$emailTemplate->addBodyButton(
420
				htmlspecialchars($trans->t('Go to poll')),
421
				$url,
422
				/** @scrutinizer ignore-type */ false
423
			);
424
			$emailTemplate->addFooter($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.'));
425
426
			try {
427
				$this->sendMail($emailTemplate, $subscription->getUserId());
428
			} catch (Exception $e) {
429
				$this->logger->alert('Error sending Mail to ' . $subscription->getUserId());
430
			}
431
		}
432
	}
433
}
434