Passed
Push — master ( c89268...f05a42 )
by René
04:39
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 1
Bugs 0 Features 0
Metric Value
eloc 42
c 1
b 0
f 0
dl 0
loc 61
rs 9.248
ccs 0
cts 46
cp 0
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
44
class MailService {
45
46
	/** @var IUserManager */
47
	private $userManager;
48
49
	/** @var IGroupManager */
50
	private $groupManager;
51
52
	/** @var IConfig */
53
	private $config;
54
55
	/** @var IURLGenerator */
56
	private $urlGenerator;
57
58
	/** @var IL10N */
59
	private $trans;
60
61
	/** @var IFactory */
62
	private $transFactory;
63
64
	/** @var IMailer */
65
	private $mailer;
66
67
	/** @var SubscriptionMapper */
68
	private $subscriptionMapper;
69
70
	/** @var ShareMapper */
71
	private $shareMapper;
72
73
	/** @var PollMapper */
74
	private $pollMapper;
75
76
	/** @var LogMapper */
77
	private $logMapper;
78
79
	/**
80
	 * MailService constructor.
81
	 * @param IUserManager $userManager
82
	 * @param IGroupManager $groupManager
83
	 * @param IConfig $config
84
	 * @param IURLGenerator $urlGenerator
85
	 * @param IL10N $trans
86
	 * @param IFactory $transFactory
87
	 * @param IMailer $mailer
88
	 * @param SubscriptionMapper $subscriptionMapper
89
	 * @param ShareMapper $shareMapper
90
	 * @param PollMapper $pollMapper
91
	 * @param LogMapper $logMapper
92
	 */
93
94
	public function __construct(
95
		IUserManager $userManager,
96
		IGroupManager $groupManager,
97
		IConfig $config,
98
		IURLGenerator $urlGenerator,
99
		IL10N $trans,
100
		IFactory $transFactory,
101
		IMailer $mailer,
102
		ShareMapper $shareMapper,
103
		SubscriptionMapper $subscriptionMapper,
104
		PollMapper $pollMapper,
105
		LogMapper $logMapper
106
	) {
107
		$this->config = $config;
108
		$this->userManager = $userManager;
109
		$this->groupManager = $groupManager;
110
		$this->urlGenerator = $urlGenerator;
111
		$this->trans = $trans;
112
		$this->transFactory = $transFactory;
113
		$this->mailer = $mailer;
114
		$this->shareMapper = $shareMapper;
115
		$this->subscriptionMapper = $subscriptionMapper;
116
		$this->pollMapper = $pollMapper;
117
		$this->logMapper = $logMapper;
118
	}
119
120
121
	/**
122
	 * sendMail - Send eMail and evaluate recipient's mail address
123
	 * and displayname if $userId is a site user
124
	 * @param IEmailTemplate $emailTemplate
125
	 * @param String $userId
126
	 * @param String $emailAddress, ignored, when $userId is set
127
	 * @param String $displayName, ignored, when $userId is set
128
	 * @return String
129
	 */
130
131
	private function sendMail($emailTemplate, $userId = '', $emailAddress = '', $displayName = '') {
132
		if ($this->userManager->get($userId) instanceof IUser) {
133
			$emailAddress = \OC::$server->getConfig()->getUserValue($userId, 'settings', 'email');
134
			$displayName = $this->userManager->get($userId)->getDisplayName();
135
		}
136
137
		if (!$emailAddress || !filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
138
			throw new Exception('Invalid email address (' . $emailAddress . ')');
139
		}
140
141
		try {
142
			$message = $this->mailer->createMessage();
143
			$message->setTo([$emailAddress => $displayName]);
144
			$message->useTemplate($emailTemplate);
145
			$this->mailer->send($message);
146
147
			return null;
148
		} catch (\Exception $e) {
149
			\OC::$server->getLogger()->logException($e, ['app' => 'polls']);
150
			throw $e;
151
		}
152
	}
153
154
155
	/**
156
	 * @param integer $pollId
157
	 * @param string $userId
158
	 * @return string
159
	 */
160
	public function resolveEmailAddress($pollId, $userId) {
161
		if ($this->userManager->get($userId) instanceof IUser) {
162
			return \OC::$server->getConfig()->getUserValue($userId, 'settings', 'email');
163
		}
164
165
		// if $userId is no site user, eval via shares
166
		try {
167
			$share = $this->shareMapper->findByPollAndUser($pollId, $userId);
168
			if ($share->getUserEmail()) {
169
				return $share->getUserEmail();
170
			}
171
		} catch (\Exception $e) {
172
			// catch silently
173
		}
174
		return $userId;
175
	}
176
177
178
	/**
179
	 * @param Share $share
180
	 * @param String $defaultLang
181
	 * @param String $skipUser
182
	 * @return Array $recipients
183
	 */
184
	private function getRecipientsByShare($share, $defaultLang = 'en', $skipUser = null) {
185
		$recipients = [];
186
		$contactsManager = \OC::$server->getContactsManager();
187
188
		if ($share->getType() === 'user') {
189
			$recipients[] = [
190
				'userId' => $share->getUserId(),
191
				'eMailAddress' => \OC::$server->getConfig()->getUserValue($share->getUserId(), 'settings', 'email'),
192
				'displayName' => $this->userManager->get($share->getUserId())->getDisplayName(),
193
				'language' => $this->config->getUserValue(
194
					$share->getUserId(),
195
					'core', 'lang'
196
				),
197
				'link' => $this->urlGenerator->linkToRouteAbsolute(
198
					'polls.page.indexvote',
199
					['id' => $share->getPollId()]
200
				)
201
			];
202
		} elseif ($share->getType() === 'email') {
203
			$recipients[] = [
204
				'userId' => $share->getUserEmail(),
205
				'eMailAddress' => $share->getUserEmail(),
206
				'displayName' => $share->getUserEmail(),
207
				'language' => $defaultLang,
208
				'link' => $this->urlGenerator->linkToRouteAbsolute(
209
					'polls.page.vote_publicpublic',
210
					['token' => $share->getToken()]
211
				)
212
			];
213
		} elseif ($share->getType() === 'contact') {
214
			$contacts = $contactsManager->search($share->getUserId(), ['FN']);
215
			if (is_array($contacts)) {
216
				$contact = $contacts[0];
0 ignored issues
show
Unused Code introduced by
The assignment to $contact is dead and can be removed.
Loading history...
217
218
				$recipients[] = [
219
					'userId' => $share->getUserId(),
220
					'eMailAddress' => $share->getUserEmail(),
221
					'displayName' => $share->getUserId(),
222
					'language' => $defaultLang,
223
					'link' => $this->urlGenerator->linkToRouteAbsolute(
224
						'polls.page.vote_publicpublic',
225
						['token' => $share->getToken()]
226
					)
227
				];
228
			} else {
229
				return;
230
			}
231
		} elseif ($share->getType() === 'external') {
232
			$recipients[] = [
233
				'userId' => $share->getUserId(),
234
				'eMailAddress' => $share->getUserEmail(),
235
				'displayName' => $share->getUserId(),
236
				'language' => $defaultLang,
237
				'link' => $this->urlGenerator->linkToRouteAbsolute(
238
					'polls.page.vote_publicpublic',
239
					['token' => $share->getToken()]
240
				)
241
			];
242
		} elseif ($share->getType() === 'group') {
243
			$groupMembers = array_keys($this->groupManager->displayNamesInGroup($share->getUserId()));
244
245
			foreach ($groupMembers as $member) {
246
				if ($skipUser === $member || !$this->userManager->get($member)->isEnabled()) {
247
					continue;
248
				}
249
250
				$recipients[] = [
251
					'userId' => $member,
252
					'eMailAddress' => \OC::$server->getConfig()->getUserValue($member, 'settings', 'email'),
253
					'displayName' => $this->userManager->get($member)->getDisplayName(),
254
					'language' => $this->config->getUserValue($member, 'core', 'lang'),
255
					'link' => $this->urlGenerator->linkToRouteAbsolute(
256
						'polls.page.indexvote', ['id' => $share->getPollId()]
257
					)
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->linkToRouteAbsolute(
360
				'polls.page.indexvote',
361
				['id' => $subscription->getPollId()]
362
			);
363
364
			$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
365
				'title' => $poll->getTitle(),
366
				'link' => $url
367
			]);
368
			$emailTemplate->setSubject($trans->t('Polls App - New Activity'));
369
			$emailTemplate->addHeader();
370
			$emailTemplate->addHeading($trans->t('Polls App - New Activity'), false);
371
			$emailTemplate->addBodyText(str_replace(
372
				['{title}'],
373
				[$poll->getTitle()],
374
				$trans->t('"{title}" had recent activity: ')
375
			));
376
377
			foreach ($log as $logItem) {
378
				if ($logItem->getPollId() === $subscription->getPollId()) {
379
					if ($poll->getAnonymous() || $poll->getShowResults() !== "always") {
380
						$displayUser = $trans->t('A user');
381
					} elseif ($this->userManager->get($logItem->getUserId()) instanceof IUser) {
382
						$displayUser = $this->userManager->get($logItem->getUserId())->getDisplayName();
383
					} else {
384
						$displayUser = $logItem->getUserId();
385
					}
386
387
					if ($logItem->getMessage()) {
388
						$emailTemplate->addBodyText($logItem->getMessage());
389
					} elseif ($logItem->getMessageId() === 'setVote') {
390
						$emailTemplate->addBodyText($trans->t(
391
							'- %s voted.',
392
							[$displayUser]
393
						));
394
					} elseif ($logItem->getMessageId() === 'updatePoll') {
395
						$emailTemplate->addBodyText($trans->t(
396
							'- %s updated the poll configuration. Please check your votes.',
397
							[$displayUser]
398
						));
399
					} elseif ($logItem->getMessageId() === 'deletePoll') {
400
						$emailTemplate->addBodyText($trans->t(
401
							'- %s deleted the poll.',
402
							[$displayUser]
403
						));
404
					} elseif ($logItem->getMessageId() === 'restorePoll') {
405
						$emailTemplate->addBodyText($trans->t(
406
							'- %s restored the poll.',
407
							[$displayUser]
408
						));
409
					} elseif ($logItem->getMessageId() === 'expirePoll') {
410
						$emailTemplate->addBodyText($trans->t(
411
							'- The poll expired.',
412
							[$displayUser]
413
						));
414
					} elseif ($logItem->getMessageId() === 'addOption') {
415
						$emailTemplate->addBodyText($trans->t(
416
							'- %s added a vote option.',
417
							[$displayUser]
418
						));
419
					} elseif ($logItem->getMessageId() === 'deleteOption') {
420
						$emailTemplate->addBodyText($trans->t(
421
							'- %s removed a vote option.',
422
							[$displayUser]
423
						));
424
					} else {
425
						$emailTemplate->addBodyText(
426
							$logItem->getMessageId() . " (" . $displayUser . ")"
427
						);
428
					}
429
				}
430
431
				$logItem->setProcessed(time());
432
				$this->logMapper->update($logItem);
433
			}
434
435
			$emailTemplate->addBodyButton(
436
				htmlspecialchars($trans->t('Go to poll')),
437
				$url,
438
				/** @scrutinizer ignore-type */ false
439
			);
440
			$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.'));
441
442
			try {
443
				$this->sendMail($emailTemplate, $subscription->getUserId(), $emailAddress, $displayName);
444
			} catch (Exception $e) {
445
				\OC::$server->getLogger()->alert('Error sending Mail to ' . $subscription->getUserId());
446
			}
447
		}
448
	}
449
}
450