Passed
Pull Request — master (#875)
by René
03:44
created

MailService::getRecipientsByShare()   C

Complexity

Conditions 10
Paths 7

Size

Total Lines 107
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 5
Bugs 2 Features 1
Metric Value
cc 10
eloc 63
c 5
b 2
f 1
nc 7
nop 3
dl 0
loc 107
ccs 0
cts 84
cp 0
crap 110
rs 6.9406

How to fix   Long Method    Complexity   

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
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
			// $this->logger->debug('User share ' . json_encode($share));
156
157
			$recipients[] = array(
158
				'userId' => $share->getUserId(),
159
				'eMailAddress' => null,
160
				'displayName' => null,
161
				'language' => $this->config->getUserValue(
162
					$share->getUserId(),
163
					'core', 'lang'
164
				),
165
				'link' => $this->urlGenerator->getAbsoluteURL(
166
					$this->urlGenerator->linkToRoute(
167
						'polls.page.indexvote',
168
						array('id' => $share->getPollId())
169
					)
170
				)
171
			);
172
173
		} elseif ($share->getType() === 'email') {
174
			// $this->logger->debug('User share ' . json_encode($share));
175
176
			$recipients[] = array(
177
				'userId' => $share->getUserEmail(),
178
				'eMailAddress' => $share->getUserEmail(),
179
				'displayName' => $share->getUserEmail(),
180
				'language' => $defaultLang,
181
				'link' => $this->urlGenerator->getAbsoluteURL(
182
					$this->urlGenerator->linkToRoute(
183
						'polls.page.vote_publicpublic',
184
						array('token' => $share->getToken())
185
					)
186
				)
187
			);
188
189
		} elseif ($share->getType() === 'contact') {
190
			// $this->logger->debug('Contact share ' . json_encode($share));
191
			$contacts = $contactsManager->search($share->getUserId(), array('FN'));
192
			if (is_array($contacts)) {
193
				$contact = $contacts[0];
194
195
				$recipients[] = array(
196
					'userId' => $share->getUserId(),
197
					'eMailAddress' => $contact['EMAIL'][0],
198
					'displayName' => $contact['FN'],
199
					'language' => $defaultLang,
200
					'link' => $this->urlGenerator->getAbsoluteURL(
201
						$this->urlGenerator->linkToRoute(
202
							'polls.page.vote_publicpublic',
203
							array('token' => $share->getToken())
204
						)
205
					)
206
				);
207
			} else {
208
				return;
209
			}
210
211
		} elseif ($share->getType() === 'external' || $share->getType() === 'email') {
212
			// $this->logger->debug('External share ' . json_encode($share));
213
214
			$recipients[] = array(
215
				'userId' => $share->getUserId(),
216
				'eMailAddress' => $share->getUserEmail(),
217
				'displayName' => $share->getUserId(),
218
				'language' => $defaultLang,
219
				'link' => $this->urlGenerator->getAbsoluteURL(
220
					$this->urlGenerator->linkToRoute(
221
						'polls.page.vote_publicpublic',
222
						array('token' => $share->getToken())
223
					)
224
				)
225
			);
226
227
		} elseif ($share->getType() === 'group') {
228
			// $this->logger->debug('Group share ' . json_encode($share));
229
230
			$groupMembers = array_keys($this->groupManager->displayNamesInGroup($share->getUserId()));
231
			// $this->logger->debug('Members are ' . json_encode($groupMembers));
232
233
			foreach ($groupMembers as $member) {
234
				if ($skipUser === $member) {
235
					// $this->logger->debug('skip ' . $skipUser);
236
					continue;
237
				}
238
				// $this->logger->debug('add ' . $member);
239
240
				$recipients[] = array(
241
					'userId' => $member,
242
					'eMailAddress' => null,
243
					'displayName' => null,
244
					'language' => $this->config->getUserValue($share->getUserId(), 'core', 'lang'),
245
					'link' => $this->urlGenerator->getAbsoluteURL(
246
						$this->urlGenerator->linkToRoute(
247
							'polls.page.indexvote', ['id' => $share->getPollId()]
248
						)
249
					)
250
				);
251
252
			}
253
		}
254
		// $this->logger->debug('Recipients: ' . json_encode($recipients));
255
256
		return $recipients;
257
	}
258
259
	/**
260
	 * @param string $token
261
	 */
262
	public function sendInvitationMail($token) {
263
264
		$share = $this->shareMapper->findByToken($token);
265
		$poll = $this->pollMapper->find($share->getPollId());
266
		$owner = $this->userManager->get($poll->getOwner());
267
		$sentMails = [];
268
		$abortedMails = [];
269
		// $this->logger->debug('Search users for token ' . $token);
270
		$recipients = $this->getRecipientsByShare(
271
			$this->shareMapper->findByToken($token),
272
			$this->config->getUserValue($poll->getOwner(), 'core', 'lang'),
273
			$poll->getOwner()
274
		);
275
276
		// $this->logger->debug('Found these recipients: ' . json_encode($recipients));
277
		foreach ($recipients as $recipient) {
278
			$trans = $this->transFactory->get('polls', $recipient['language']);
279
280
			// $this->logger->debug('Build eMailTemplate for  ' . $recipient['userId']);
281
282
			$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
283
				'owner' => $owner->getDisplayName(),
284
				'title' => $poll->getTitle(),
285
				'link' => $recipient['link']
286
			]);
287
288
			$emailTemplate->setSubject($trans->t('Poll invitation "%s"', $poll->getTitle()));
289
			$emailTemplate->addHeader();
290
			$emailTemplate->addHeading($trans->t('Poll invitation "%s"', $poll->getTitle()), false);
291
292
			$emailTemplate->addBodyText(str_replace(
293
				['{owner}', '{title}'],
294
				[$owner->getDisplayName(), $poll->getTitle()],
295
				$trans->t('{owner} invited you to take part in the poll "{title}"')
296
			));
297
298
			$emailTemplate->addBodyButton(
299
				htmlspecialchars($trans->t('Go to poll')),
300
				$recipient['link']
301
			);
302
303
			$emailTemplate->addFooter($trans->t('This email is sent to you, because you are invited to vote in this poll by the poll owner.'));
304
305
			try {
306
				// $this->logger->debug('Send Mail to ' . $recipient);
307
308
				$this->sendMail(
309
					$emailTemplate,
310
					$recipient['userId'],
311
					$recipient['eMailAddress'],
312
					$recipient['displayName']
313
				);
314
				$sentMails[] = $recipient;
315
			} catch (Exception $e) {
316
				$abortedMails[] = $recipient;
317
				$this->logger->alert('Error sending Mail to ' . json_encode($recipient));
318
			}
319
		}
320
		return ['sentMails' => $sentMails, 'abortedMails' => $abortedMails];
321
	}
322
323
	public function sendNotifications() {
324
		$subscriptions = [];
325
		$log = $this->logMapper->findUnprocessedPolls();
326
327
		foreach ($log as $logItem) {
328
			$subscriptions = array_merge($subscriptions, $this->subscriptionMapper->findAllByPoll($logItem->getPollId()));
329
		}
330
331
		$log = $this->logMapper->findUnprocessed();
332
333
		foreach ($subscriptions as $subscription) {
334
335
			if ($this->userManager->get($subscription->getUserId()) instanceof IUser) {
336
				$lang = $this->config->getUserValue($subscription->getUserId(), 'core', 'lang');
337
			} else {
338
				continue;
339
			}
340
341
			$poll = $this->pollMapper->find($subscription->getPollId());
342
			$trans = $this->transFactory->get('polls', $lang);
343
344
			$url = $this->urlGenerator->getAbsoluteURL(
345
				$this->urlGenerator->linkToRoute(
346
					'polls.page.indexvote',
347
					array('id' => $subscription->getPollId())
348
				)
349
			);
350
351
			$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
352
				'title' => $poll->getTitle(),
353
				'link' => $url
354
			]);
355
			$emailTemplate->setSubject($trans->t('Polls App - New Activity'));
356
			$emailTemplate->addHeader();
357
			$emailTemplate->addHeading($trans->t('Polls App - New Activity'), false);
358
			$emailTemplate->addBodyText(str_replace(
359
				['{title}'],
360
				[$poll->getTitle()],
361
				$trans->t('"{title}" had recent activity: ')
362
			));
363
364
			foreach ($log as $logItem) {
365
				if ($logItem->getPollId() === $subscription->getPollId()) {
366
367
					if ($this->userManager->get($logItem->getUserId()) instanceof IUser) {
368
						$displayUser = $this->userManager->get($logItem->getUserId())->getDisplayName();
369
					} else {
370
						$displayUser = $logItem->getUserId();
371
					}
372
373
					if ($logItem->getMessage()) {
374
						$emailTemplate->addBodyText($logItem->getMessage());
375
376
					} elseif ($logItem->getMessageId() === 'setVote') {
377
						$emailTemplate->addBodyText($trans->t(
378
							'- %s voted.',
379
							array($displayUser)
380
						));
381
382
					} elseif ($logItem->getMessageId() === 'updatePoll') {
383
						$emailTemplate->addBodyText($trans->t(
384
							'- %s updated the poll configuration. Please check your votes.',
385
							array($displayUser)
386
						));
387
388
					} elseif ($logItem->getMessageId() === 'deletePoll') {
389
						$emailTemplate->addBodyText($trans->t(
390
							'- %s deleted the poll.',
391
							array($displayUser)
392
						));
393
394
					} elseif ($logItem->getMessageId() === 'restorePoll') {
395
						$emailTemplate->addBodyText($trans->t(
396
							'- %s restored the poll.',
397
							array($displayUser)
398
						));
399
400
					} elseif ($logItem->getMessageId() === 'expirePoll') {
401
						$emailTemplate->addBodyText($trans->t(
402
							'- The poll expired.',
403
							array($displayUser)
404
						));
405
406
					} elseif ($logItem->getMessageId() === 'addOption') {
407
						$emailTemplate->addBodyText($trans->t(
408
							'- %s added a vote option.',
409
							array($displayUser)
410
						));
411
412
					} elseif ($logItem->getMessageId() === 'deleteOption') {
413
						$emailTemplate->addBodyText($trans->t(
414
							'- %s removed a vote option.',
415
							array($displayUser)
416
						));
417
418
					} else {
419
						$emailTemplate->addBodyText(
420
							$logItem->getMessageId() . " (" . $displayUser . ")"
421
						);
422
					}
423
				}
424
425
				$logItem->setProcessed(time());
426
				$this->logMapper->update($logItem);
427
			}
428
429
			$emailTemplate->addBodyButton(
430
				htmlspecialchars($trans->t('Go to poll')),
431
				$url,
432
				/** @scrutinizer ignore-type */ false
433
			);
434
			$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.'));
435
436
			try {
437
				$this->sendMail($emailTemplate, $subscription->getUserId());
438
			} catch (Exception $e) {
439
				$this->logger->alert('Error sending Mail to ' . $subscription->getUserId());
440
				// TODO: alert Owner
441
			}
442
		}
443
	}
444
}
445