Passed
Pull Request — master (#1128)
by René
08:09 queued 03:52
created

MailService::sendInvitationMail()   A

Complexity

Conditions 3
Paths 6

Size

Total Lines 61
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 42
c 2
b 0
f 0
dl 0
loc 61
ccs 0
cts 46
cp 0
rs 9.248
cc 3
nc 6
nop 1
crap 12

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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