Passed
Pull Request — master (#1234)
by René
04:00
created

MailService   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 323
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 8
Bugs 2 Features 1
Metric Value
wmc 33
eloc 175
dl 0
loc 323
ccs 0
cts 215
cp 0
rs 9.76
c 8
b 2
f 1

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 24 1
B sendNotifications() 0 39 6
A sendInvitation() 0 29 4
A generateInvitation() 0 33 2
A sendMail() 0 15 4
C generateNotification() 0 92 16
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 OCP\IUser;
27
use OCP\IUserManager;
28
use OCP\IGroupManager;
29
use OCP\IConfig;
30
use OCP\IURLGenerator;
31
use OCP\IL10N;
32
use OCP\L10N\IFactory;
33
use OCP\Mail\IMailer;
34
use OCP\Mail\IEMailTemplate;
35
36
use OCA\Polls\Db\SubscriptionMapper;
37
use OCA\Polls\Db\PollMapper;
38
use OCA\Polls\Db\ShareMapper;
39
use OCA\Polls\Db\LogMapper;
40
use OCA\Polls\Db\Log;
41
use OCA\Polls\Model\Email;
42
use OCA\Polls\Model\User;
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, $emailAddress, $displayName) {
132
		if (!$emailAddress || !filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
133
			throw new \Exception('Invalid email address (' . $emailAddress . ')');
134
		}
135
136
		try {
137
			$message = $this->mailer->createMessage();
138
			$message->setTo([$emailAddress => $displayName]);
139
			$message->useTemplate($emailTemplate);
140
			$this->mailer->send($message);
141
142
			return null;
143
		} catch (\Exception $e) {
144
			\OC::$server->getLogger()->logException($e->getMessage(), ['app' => 'polls']);
145
			throw $e;
146
		}
147
	}
148
149
	/**
150
	 * @param string $token
151
	 */
152
	public function sendInvitation($token) {
153
		$share = $this->shareMapper->findByToken($token);
154
		$poll = $this->pollMapper->find($share->getPollId());
155
		$sentMails = [];
156
		$abortedMails = [];
157
158
		foreach ($share->getMembers() as $recipient) {
159
			//skip poll owner
160
			if ($recipient->getId() === $poll->getOwner()) {
161
				continue;
162
			}
163
164
			$emailTemplate = $this->generateInvitation($recipient, $poll, $share->getURL());
165
166
			try {
167
				$this->sendMail(
168
					$emailTemplate,
169
					$recipient->getEmailAddress(),
170
					$recipient->getDisplayName()
171
				);
172
				$share->setInvitationSent(time());
173
				$this->shareMapper->update($share);
174
				$sentMails[] = $recipient->getId();
175
			} catch (\Exception $e) {
176
				$abortedMails[] = $recipient->getId();
177
				\OC::$server->getLogger()->alert('Error sending Mail to ' . json_encode($recipient));
178
			}
179
		}
180
		return ['sentMails' => $sentMails, 'abortedMails' => $abortedMails];
181
	}
182
183
	public function sendNotifications() {
184
		$subscriptions = [];
185
		$log = $this->logMapper->findUnprocessedPolls();
186
187
		foreach ($log as $logItem) {
188
			$subscriptions = array_merge($subscriptions, $this->subscriptionMapper->findAllByPoll($logItem->getPollId()));
189
		}
190
191
		$log = $this->logMapper->findUnprocessed();
192
193
		foreach ($subscriptions as $subscription) {
194
			$poll = $this->pollMapper->find($subscription->getPollId());
195
196
			if ($this->userManager->get($subscription->getUserId()) instanceof IUser) {
197
				$recipient = new User($subscription->getUserId());
198
				$url = $this->urlGenerator->linkToRouteAbsolute(
199
					'polls.page.vote',
200
					['id' => $subscription->getPollId()]
201
				);
202
			} else {
203
				try {
204
					$share = $this->shareMapper->findByPollAndUser($subscription->getPollId(), $subscription->getUserId());
205
					$recipient = $share->getUserObject();
206
					$url = $share->getURL();
207
				} catch (\Exception $e) {
208
					continue;
209
				}
210
			}
211
212
			$emailTemplate = $this->generateNotification($recipient, $poll, $url, $log);
213
214
			try {
215
				$this->sendMail(
216
					$emailTemplate,
217
					$recipient->getEmailAddress(),
218
					$recipient->getDisplayName()
219
				);
220
			} catch (\Exception $e) {
221
				\OC::$server->getLogger()->alert('Error sending Mail to ' . $recipient->getId());
222
			}
223
		}
224
	}
225
226
	/**
227
	 * generateNotification
228
	 * @param UserGroupClass $recipient
0 ignored issues
show
Bug introduced by
The type OCA\Polls\Service\UserGroupClass was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
229
	 * @param Poll $poll
230
	 * @return Object $emailTemplate
231
	 */
232
233
	private function generateNotification($recipient, $poll, $url, $log) {
234
		$owner = $poll->getOwnerUserObject();
235
		if ($recipient->getLanguage()) {
236
			$trans = $this->transFactory->get('polls', $recipient->getLanguage());
237
		} else {
238
			$trans = $this->transFactory->get('polls', $owner->getLanguage());
239
		}
240
		$emailTemplate = $this->mailer->createEMailTemplate('polls.Notification', [
241
			'title' => $poll->getTitle(),
242
			'link' => $url
243
		]);
244
245
		$emailTemplate->setSubject($trans->t('Polls App - New Activity'));
246
		$emailTemplate->addHeader();
247
		$emailTemplate->addHeading($trans->t('Polls App - New Activity'), false);
248
		$emailTemplate->addBodyText(str_replace(
249
			['{title}'],
250
			[$poll->getTitle()],
251
			$trans->t('"{title}" had recent activity: ')
252
		));
253
		foreach ($log as $logItem) {
254
			if ($logItem->getPollId() === $poll->getId()) {
255
				if ($poll->getAnonymous() || $poll->getShowResults() !== "always") {
256
					$displayUser = $trans->t('A user');
257
				} elseif ($this->userManager->get($logItem->getUserId()) instanceof IUser) {
258
					$actor = new User($subscription->getUserId());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $subscription seems to be never defined.
Loading history...
259
					$displayUser = $actor->getDisplayName();
260
				} else {
261
					try {
262
						$share = $this->shareMapper->findByPollAndUser($subscription->getPollId(), $logItem->getUserId());
263
						$displayUser = $share->getUserObject()->getDisplayName();
264
					} catch (\Exception $e) {
265
						$displayUser = $logItem->getUserId();
266
					}
267
				}
268
269
				if ($logItem->getMessage()) {
270
					$emailTemplate->addBodyText($logItem->getMessage());
271
				} elseif ($logItem->getMessageId() === Log::MSG_ID_SETVOTE) {
272
					$emailTemplate->addBodyText($trans->t(
273
						'- %s voted.',
274
						[$displayUser]
275
					));
276
				} elseif ($logItem->getMessageId() === Log::MSG_ID_UPDATEPOLL) {
277
					$emailTemplate->addBodyText($trans->t(
278
						'- Updated poll configuration. Please check your votes.',
279
						[$displayUser]
280
					));
281
				} elseif ($logItem->getMessageId() === Log::MSG_ID_DELETEPOLL) {
282
					$emailTemplate->addBodyText($trans->t(
283
						'- The poll got deleted.',
284
						[$displayUser]
285
					));
286
				} elseif ($logItem->getMessageId() === Log::MSG_ID_RESTOREPOLL) {
287
					$emailTemplate->addBodyText($trans->t(
288
						'- The poll got restored.',
289
						[$displayUser]
290
					));
291
				} elseif ($logItem->getMessageId() === Log::MSG_ID_EXPIREPOLL) {
292
					$emailTemplate->addBodyText($trans->t(
293
						'- The poll closed.',
294
						[$displayUser]
295
					));
296
				} elseif ($logItem->getMessageId() === Log::MSG_ID_ADDOPTION) {
297
					$emailTemplate->addBodyText($trans->t(
298
						'- A vote option was added.',
299
						[$displayUser]
300
					));
301
				} elseif ($logItem->getMessageId() === Log::MSG_ID_DELETEOPTION) {
302
					$emailTemplate->addBodyText($trans->t(
303
						'- A vote option was removed.',
304
						[$displayUser]
305
					));
306
				} else {
307
					$emailTemplate->addBodyText(
308
						$logItem->getMessageId() . " (" . $displayUser . ")"
309
					);
310
				}
311
			}
312
313
			$logItem->setProcessed(time());
314
			$this->logMapper->update($logItem);
315
		}
316
317
		$emailTemplate->addBodyButton(
318
			htmlspecialchars($trans->t('Go to poll')),
319
			$url,
320
			/** @scrutinizer ignore-type */ false
321
		);
322
		$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.'));
323
324
		return $emailTemplate;
325
	}
326
327
	/**
328
	 * generateInvitation
329
	 * @param UserGroupClass $recipient
330
	 * @param Poll $poll
331
	 * @return Object $emailTemplate
332
	 */
333
334
	private function generateInvitation($recipient, $poll, $url) {
335
		$owner = $poll->getOwnerUserObject();
336
		if ($recipient->getLanguage()) {
337
			$trans = $this->transFactory->get('polls', $recipient->getLanguage());
338
		} else {
339
			$trans = $this->transFactory->get('polls', $owner->getLanguage());
340
		}
341
342
		$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
343
			'owner' => $owner->getDisplayName(),
344
			'title' => $poll->getTitle(),
345
			'link' => $url
346
		]);
347
348
		$emailTemplate->setSubject($trans->t('Poll invitation "%s"', $poll->getTitle()));
349
		$emailTemplate->addHeader();
350
		$emailTemplate->addHeading($trans->t('Poll invitation "%s"', $poll->getTitle()), false);
351
		$emailTemplate->addBodyText(str_replace(
352
				['{owner}', '{title}'],
353
				[$owner->getDisplayName(), $poll->getTitle()],
354
				$trans->t('{owner} invited you to take part in the poll "{title}"')
355
			));
356
		$emailTemplate->addBodyText($poll->getDescription());
357
		$emailTemplate->addBodyButton(
358
				htmlspecialchars($trans->t('Go to poll')),
359
				$url
360
			);
361
		$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: '));
362
		$emailTemplate->addBodyText($url);
363
		$emailTemplate->addBodyText($trans->t('Do not share this link with other people, because it is connected to your votes.'));
364
		$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.'));
365
366
		return $emailTemplate;
367
	}
368
}
369