Passed
Pull Request — master (#875)
by René
03:59
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
270
		$recipients = $this->getRecipientsByShare(
271
			$this->shareMapper->findByToken($token),
272
			$this->config->getUserValue($poll->getOwner(), 'core', 'lang'),
273
			$poll->getOwner()
274
		);
275
276
		foreach ($recipients as $recipient) {
277
			$trans = $this->transFactory->get('polls', $recipient['language']);
278
279
280
			$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
281
				'owner' => $owner->getDisplayName(),
282
				'title' => $poll->getTitle(),
283
				'link' => $recipient['link']
284
			]);
285
286
			$emailTemplate->setSubject($trans->t('Poll invitation "%s"', $poll->getTitle()));
287
			$emailTemplate->addHeader();
288
			$emailTemplate->addHeading($trans->t('Poll invitation "%s"', $poll->getTitle()), false);
289
290
			$emailTemplate->addBodyText(str_replace(
291
				['{owner}', '{title}'],
292
				[$owner->getDisplayName(), $poll->getTitle()],
293
				$trans->t('{owner} invited you to take part in the poll "{title}"')
294
			));
295
296
			$emailTemplate->addBodyButton(
297
				htmlspecialchars($trans->t('Go to poll')),
298
				$recipient['link']
299
			);
300
301
			$emailTemplate->addBodyText( $trans->t('This link gives you personal access to the poll named above. </br> Press the button above or copy the following link and add it in your browser\'s location bar: ') );
302
			$emailTemplate->addBodyText( $recipient['link'] );
303
304
			$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.'));
305
306
			try {
307
				// $this->logger->debug('Send Mail to ' . $recipient);
308
309
				$this->sendMail(
310
					$emailTemplate,
311
					$recipient['userId'],
312
					$recipient['eMailAddress'],
313
					$recipient['displayName']
314
				);
315
				$sentMails[] = $recipient;
316
			} catch (Exception $e) {
317
				$abortedMails[] = $recipient;
318
				$this->logger->alert('Error sending Mail to ' . json_encode($recipient));
319
			}
320
		}
321
		return ['sentMails' => $sentMails, 'abortedMails' => $abortedMails];
322
	}
323
324
	public function sendNotifications() {
325
		$subscriptions = [];
326
		$log = $this->logMapper->findUnprocessedPolls();
327
328
		foreach ($log as $logItem) {
329
			$subscriptions = array_merge($subscriptions, $this->subscriptionMapper->findAllByPoll($logItem->getPollId()));
330
		}
331
332
		$log = $this->logMapper->findUnprocessed();
333
334
		foreach ($subscriptions as $subscription) {
335
336
			if ($this->userManager->get($subscription->getUserId()) instanceof IUser) {
337
				$lang = $this->config->getUserValue($subscription->getUserId(), 'core', 'lang');
338
			} else {
339
				continue;
340
			}
341
342
			$poll = $this->pollMapper->find($subscription->getPollId());
343
			$trans = $this->transFactory->get('polls', $lang);
344
345
			$url = $this->urlGenerator->getAbsoluteURL(
346
				$this->urlGenerator->linkToRoute(
347
					'polls.page.indexvote',
348
					array('id' => $subscription->getPollId())
349
				)
350
			);
351
352
			$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
353
				'title' => $poll->getTitle(),
354
				'link' => $url
355
			]);
356
			$emailTemplate->setSubject($trans->t('Polls App - New Activity'));
357
			$emailTemplate->addHeader();
358
			$emailTemplate->addHeading($trans->t('Polls App - New Activity'), false);
359
			$emailTemplate->addBodyText(str_replace(
360
				['{title}'],
361
				[$poll->getTitle()],
362
				$trans->t('"{title}" had recent activity: ')
363
			));
364
365
			foreach ($log as $logItem) {
366
				if ($logItem->getPollId() === $subscription->getPollId()) {
367
368
					if ($this->userManager->get($logItem->getUserId()) instanceof IUser) {
369
						$displayUser = $this->userManager->get($logItem->getUserId())->getDisplayName();
370
					} else {
371
						$displayUser = $logItem->getUserId();
372
					}
373
374
					if ($logItem->getMessage()) {
375
						$emailTemplate->addBodyText($logItem->getMessage());
376
377
					} elseif ($logItem->getMessageId() === 'setVote') {
378
						$emailTemplate->addBodyText($trans->t(
379
							'- %s voted.',
380
							array($displayUser)
381
						));
382
383
					} elseif ($logItem->getMessageId() === 'updatePoll') {
384
						$emailTemplate->addBodyText($trans->t(
385
							'- %s updated the poll configuration. Please check your votes.',
386
							array($displayUser)
387
						));
388
389
					} elseif ($logItem->getMessageId() === 'deletePoll') {
390
						$emailTemplate->addBodyText($trans->t(
391
							'- %s deleted the poll.',
392
							array($displayUser)
393
						));
394
395
					} elseif ($logItem->getMessageId() === 'restorePoll') {
396
						$emailTemplate->addBodyText($trans->t(
397
							'- %s restored the poll.',
398
							array($displayUser)
399
						));
400
401
					} elseif ($logItem->getMessageId() === 'expirePoll') {
402
						$emailTemplate->addBodyText($trans->t(
403
							'- The poll expired.',
404
							array($displayUser)
405
						));
406
407
					} elseif ($logItem->getMessageId() === 'addOption') {
408
						$emailTemplate->addBodyText($trans->t(
409
							'- %s added a vote option.',
410
							array($displayUser)
411
						));
412
413
					} elseif ($logItem->getMessageId() === 'deleteOption') {
414
						$emailTemplate->addBodyText($trans->t(
415
							'- %s removed a vote option.',
416
							array($displayUser)
417
						));
418
419
					} else {
420
						$emailTemplate->addBodyText(
421
							$logItem->getMessageId() . " (" . $displayUser . ")"
422
						);
423
					}
424
				}
425
426
				$logItem->setProcessed(time());
427
				$this->logMapper->update($logItem);
428
			}
429
430
			$emailTemplate->addBodyButton(
431
				htmlspecialchars($trans->t('Go to poll')),
432
				$url,
433
				/** @scrutinizer ignore-type */ false
434
			);
435
			$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.'));
436
437
			try {
438
				$this->sendMail($emailTemplate, $subscription->getUserId());
439
			} catch (Exception $e) {
440
				$this->logger->alert('Error sending Mail to ' . $subscription->getUserId());
441
				// TODO: alert Owner
442
			}
443
		}
444
	}
445
}
446