MailService::getLogString()   B
last analyzed

Complexity

Conditions 10
Paths 10

Size

Total Lines 22
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
eloc 21
c 0
b 0
f 0
dl 0
loc 22
ccs 0
cts 20
cp 0
rs 7.6666
cc 10
nc 10
nop 2
crap 110

How to fix   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 Psr\Log\LoggerInterface;
27
use OCP\IUser;
28
use OCP\IUserManager;
29
use OCP\IGroupManager;
30
use OCP\IConfig;
31
use OCP\IURLGenerator;
32
use OCP\IL10N;
33
use OCP\L10N\IFactory;
34
use OCP\Mail\IMailer;
35
use OCP\Mail\IEMailTemplate;
36
use OCA\Polls\Db\SubscriptionMapper;
37
use OCA\Polls\Db\PollMapper;
38
use OCA\Polls\Db\Poll;
39
use OCA\Polls\Db\ShareMapper;
40
use OCA\Polls\Db\Share;
41
use OCA\Polls\Db\LogMapper;
42
use OCA\Polls\Db\Log;
43
use OCA\Polls\Model\UserGroupClass;
44
use OCA\Polls\Model\User;
45
46
class MailService {
47
48
	/** @var LoggerInterface */
49
	private $logger;
50
51
	/** @var string */
52
	private $appName;
53
54
	/** @var IUserManager */
55
	private $userManager;
56
57
	/** @var IGroupManager */
58
	private $groupManager;
59
60
	/** @var IConfig */
61
	private $config;
62
63
	/** @var IURLGenerator */
64
	private $urlGenerator;
65
66
	/** @var IL10N */
67
	private $trans;
68
69
	/** @var IFactory */
70
	private $transFactory;
71
72
	/** @var IMailer */
73
	private $mailer;
74
75
	/** @var SubscriptionMapper */
76
	private $subscriptionMapper;
77
78
	/** @var ShareMapper */
79
	private $shareMapper;
80
81
	/** @var PollMapper */
82
	private $pollMapper;
83
84
	/** @var LogMapper */
85
	private $logMapper;
86
87
	public function __construct(
88
		string $AppName,
89
		LoggerInterface $logger,
90
		IUserManager $userManager,
91
		IGroupManager $groupManager,
92
		IConfig $config,
93
		IURLGenerator $urlGenerator,
94
		IL10N $trans,
95
		IFactory $transFactory,
96
		IMailer $mailer,
97
		ShareMapper $shareMapper,
98
		SubscriptionMapper $subscriptionMapper,
99
		PollMapper $pollMapper,
100
		LogMapper $logMapper
101
	) {
102
		$this->appName = $AppName;
103
		$this->logger = $logger;
104
		$this->config = $config;
105
		$this->userManager = $userManager;
106
		$this->groupManager = $groupManager;
107
		$this->urlGenerator = $urlGenerator;
108
		$this->trans = $trans;
109
		$this->transFactory = $transFactory;
110
		$this->mailer = $mailer;
111
		$this->shareMapper = $shareMapper;
112
		$this->subscriptionMapper = $subscriptionMapper;
113
		$this->pollMapper = $pollMapper;
114
		$this->logMapper = $logMapper;
115
	}
116
117
	private function sendMail(IEmailTemplate $emailTemplate, string $emailAddress, string $displayName): void {
118
		if (!$emailAddress || !filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
119
			throw new \Exception('Invalid email address (' . $emailAddress . ')');
120
		}
121
122
		try {
123
			$message = $this->mailer->createMessage();
124
			$message->setTo([$emailAddress => $displayName]);
125
			$message->useTemplate($emailTemplate);
126
			$this->mailer->send($message);
127
		} catch (\Exception $e) {
128
			$this->logger->alert($e->getMessage());
129
			throw $e;
130
		}
131
	}
132
133
	public function resolveEmailAddress(int $pollId, string $userId): string {
134
		if ($this->userManager->get($userId) instanceof IUser) {
135
			return \OC::$server->getConfig()->getUserValue($userId, 'settings', 'email');
136
		}
137
138
		// if $userId is no site user, eval via shares
139
		try {
140
			$share = $this->shareMapper->findByPollAndUser($pollId, $userId);
141
			if ($share->getEmailAddress()) {
142
				return $share->getEmailAddress();
143
			}
144
		} catch (\Exception $e) {
145
			// catch silently
146
		}
147
		return $userId;
148
	}
149
150
	public function resendInvitation(string $token): Share {
151
		$share = $this->shareMapper->findByToken($token);
152
		$poll = $this->pollMapper->find($share->getPollId());
153
		$recipient = $share->getUserObject();
154
		$emailTemplate = $this->generateInvitation($recipient, $poll, $share->getURL());
155
		$this->sendMail(
156
			$emailTemplate,
157
			$recipient->getEmailAddress(),
158
			$recipient->getDisplayName()
159
		);
160
		$share->setInvitationSent(time());
161
		return $this->shareMapper->update($share);
162
	}
163
164
	public function sendInvitation(string $token): array {
165
		$share = $this->shareMapper->findByToken($token);
166
		$poll = $this->pollMapper->find($share->getPollId());
167
		$sentMails = [];
168
		$abortedMails = [];
169
170
		foreach ($share->getMembers() as $recipient) {
171
			//skip poll owner
172
			if ($recipient->getId() === $poll->getOwner()) {
173
				continue;
174
			}
175
176
			$emailTemplate = $this->generateInvitation($recipient, $poll, $share->getURL());
177
178
			try {
179
				$this->sendMail(
180
					$emailTemplate,
181
					$recipient->getEmailAddress(),
182
					$recipient->getDisplayName()
183
				);
184
				$share->setInvitationSent(time());
185
				$this->shareMapper->update($share);
186
				$sentMails[] = $recipient->getId();
187
			} catch (\Exception $e) {
188
				$abortedMails[] = $recipient->getId();
189
				$this->logger->error('Error sending Mail to ' . json_encode($recipient));
190
			}
191
		}
192
		return ['sentMails' => $sentMails, 'abortedMails' => $abortedMails];
193
	}
194
195
	public function sendNotifications(): void {
196
		$subscriptions = [];
197
		$log = $this->logMapper->findUnprocessedPolls();
198
199
		foreach ($log as $logItem) {
200
			$subscriptions = array_merge($subscriptions, $this->subscriptionMapper->findAllByPoll($logItem->getPollId()));
201
		}
202
203
		$log = $this->logMapper->findUnprocessed();
204
205
		foreach ($subscriptions as $subscription) {
206
			$poll = $this->pollMapper->find($subscription->getPollId());
207
208
			if ($this->userManager->get($subscription->getUserId()) instanceof IUser) {
209
				$recipient = new User($subscription->getUserId());
210
				$url = $this->urlGenerator->linkToRouteAbsolute(
211
					'polls.page.vote',
212
					['id' => $subscription->getPollId()]
213
				);
214
			} else {
215
				try {
216
					$share = $this->shareMapper->findByPollAndUser($subscription->getPollId(), $subscription->getUserId());
217
					$recipient = $share->getUserObject();
218
					$url = $share->getURL();
219
				} catch (\Exception $e) {
220
					continue;
221
				}
222
			}
223
224
			$emailTemplate = $this->generateNotification($recipient, $poll, $url, $log);
225
226
			try {
227
				$this->sendMail(
228
					$emailTemplate,
229
					$recipient->getEmailAddress(),
230
					$recipient->getDisplayName()
231
				);
232
			} catch (\Exception $e) {
233
				$this->logger->error('Error sending Mail to ' . $recipient->getId());
234
			}
235
		}
236
	}
237
238
	private function getLogString(Log $logItem, string $displayName): string {
239
		switch ($logItem->getMessageId()) {
240
			case Log::MSG_ID_SETVOTE:
241
				return $this->trans->t('- %s voted.', [$displayName]);
242
			case Log::MSG_ID_UPDATEPOLL:
243
				return $this->trans->t('- Updated poll configuration. Please check your votes.');
244
			case Log::MSG_ID_DELETEPOLL:
245
				return $this->trans->t('- The poll got deleted.');
246
			case Log::MSG_ID_RESTOREPOLL:
247
				return $this->trans->t('- The poll got restored.');
248
			case Log::MSG_ID_EXPIREPOLL:
249
				return $this->trans->t('- The poll was closed.');
250
			case Log::MSG_ID_ADDOPTION:
251
				return $this->trans->t('- A vote option was added.');
252
			case Log::MSG_ID_DELETEOPTION:
253
				return $this->trans->t('- A vote option was removed.');
254
			case Log::MSG_ID_OWNERCHANGE:
255
				return $this->trans->t('- The poll owner changed.');
256
			case Log::MSG_ID_ADDPOLL:
257
				return $this->trans->t('- %s created the poll.', [$displayName]);
258
			default:
259
				return $logItem->getMessageId() . " (" . $displayName . ")";
260
		}
261
	}
262
263
	private function generateNotification(UserGroupClass $recipient, Poll $poll, string $url, array $log): IEMailTemplate {
264
		$owner = $poll->getOwnerUserObject();
265
		$this->trans = $this->transFactory->get('polls', $recipient->getLanguage() ? $recipient->getLanguage() : $owner->getLanguage());
266
		$emailTemplate = $this->mailer->createEMailTemplate('polls.Notification', [
267
			'title' => $poll->getTitle(),
268
			'link' => $url
269
		]);
270
271
		$emailTemplate->setSubject($this->trans->t('Polls App - New Activity'));
272
		$emailTemplate->addHeader();
273
		$emailTemplate->addHeading($this->trans->t('Polls App - New Activity'), false);
274
		$emailTemplate->addBodyText(str_replace(
275
			['{title}'],
276
			[$poll->getTitle()],
277
			$this->trans->t('"{title}" had recent activity: ')
278
		));
279
		foreach ($log as $logItem) {
280
			if (intval($logItem->getPollId()) === $poll->getId()) {
281
				if ($poll->getAnonymous() || $poll->getShowResults() !== "always") {
282
					$displayName = $this->trans->t('A user');
283
				} elseif ($this->userManager->get($logItem->getUserId()) instanceof IUser) {
284
					$actor = new User($logItem->getUserId());
285
					$displayName = $actor->getDisplayName();
286
				} else {
287
					try {
288
						$share = $this->shareMapper->findByPollAndUser($poll->getId(), $logItem->getUserId());
289
						$displayName = $share->getUserObject()->getDisplayName();
290
					} catch (\Exception $e) {
291
						$displayName = $logItem->getUserId();
292
					}
293
				}
294
295
				$emailTemplate->addBodyText($this->getLogString($logItem, $displayName));
296
			}
297
298
			$logItem->setProcessed(time());
299
			$this->logMapper->update($logItem);
300
		}
301
302
		$emailTemplate->addBodyButton(htmlspecialchars($this->trans->t('Go to poll')), $url, '');
303
		$emailTemplate->addFooter($this->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.'));
304
305
		return $emailTemplate;
306
	}
307
308
	private function generateInvitation(UserGroupClass $recipient, Poll $poll, string $url): IEMailTemplate {
309
		$owner = $poll->getOwnerUserObject();
310
		$this->trans = $this->transFactory->get('polls', $recipient->getLanguage() ? $recipient->getLanguage() : $owner->getLanguage());
311
312
		$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
313
			'owner' => $owner->getDisplayName(),
314
			'title' => $poll->getTitle(),
315
			'link' => $url
316
		]);
317
318
		$emailTemplate->setSubject($this->trans->t('Poll invitation "%s"', $poll->getTitle()));
319
		$emailTemplate->addHeader();
320
		$emailTemplate->addHeading($this->trans->t('Poll invitation "%s"', $poll->getTitle()), false);
321
		$emailTemplate->addBodyText(str_replace(
322
				['{owner}', '{title}'],
323
				[$owner->getDisplayName(), $poll->getTitle()],
324
				$this->trans->t('{owner} invited you to take part in the poll "{title}"')
325
			));
326
		$emailTemplate->addBodyText($poll->getDescription());
327
		$emailTemplate->addBodyButton(
328
				htmlspecialchars($this->trans->t('Go to poll')),
329
				$url
330
			);
331
		$emailTemplate->addBodyText($this->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:'));
332
		$emailTemplate->addBodyText($url);
333
		$emailTemplate->addBodyText($this->trans->t('Do not share this link with other people, because it is connected to your votes.'));
334
		$emailTemplate->addFooter($this->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.'));
335
336
		return $emailTemplate;
337
	}
338
}
339