Passed
Pull Request — master (#1234)
by René
03:57
created

MailService::getLogString()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 23
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 19
c 1
b 1
f 0
dl 0
loc 23
rs 8.0555
ccs 0
cts 18
cp 0
cc 9
nc 9
nop 2
crap 90
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\UserGroupClass;
42
use OCA\Polls\Model\Email;
43
use OCA\Polls\Model\User;
44
45
class MailService {
46
47
	/** @var IUserManager */
48
	private $userManager;
49
50
	/** @var IGroupManager */
51
	private $groupManager;
52
53
	/** @var IConfig */
54
	private $config;
55
56
	/** @var IURLGenerator */
57
	private $urlGenerator;
58
59
	/** @var IL10N */
60
	private $trans;
61
62
	/** @var IFactory */
63
	private $transFactory;
64
65
	/** @var IMailer */
66
	private $mailer;
67
68
	/** @var SubscriptionMapper */
69
	private $subscriptionMapper;
70
71
	/** @var ShareMapper */
72
	private $shareMapper;
73
74
	/** @var PollMapper */
75
	private $pollMapper;
76
77
	/** @var LogMapper */
78
	private $logMapper;
79
80
	/**
81
	 * MailService constructor.
82
	 * @param IUserManager $userManager
83
	 * @param IGroupManager $groupManager
84
	 * @param IConfig $config
85
	 * @param IURLGenerator $urlGenerator
86
	 * @param IL10N $trans
87
	 * @param IFactory $transFactory
88
	 * @param IMailer $mailer
89
	 * @param SubscriptionMapper $subscriptionMapper
90
	 * @param ShareMapper $shareMapper
91
	 * @param PollMapper $pollMapper
92
	 * @param LogMapper $logMapper
93
	 */
94
95
	public function __construct(
96
		IUserManager $userManager,
97
		IGroupManager $groupManager,
98
		IConfig $config,
99
		IURLGenerator $urlGenerator,
100
		IL10N $trans,
101
		IFactory $transFactory,
102
		IMailer $mailer,
103
		ShareMapper $shareMapper,
104
		SubscriptionMapper $subscriptionMapper,
105
		PollMapper $pollMapper,
106
		LogMapper $logMapper
107
	) {
108
		$this->config = $config;
109
		$this->userManager = $userManager;
110
		$this->groupManager = $groupManager;
111
		$this->urlGenerator = $urlGenerator;
112
		$this->trans = $trans;
113
		$this->transFactory = $transFactory;
114
		$this->mailer = $mailer;
115
		$this->shareMapper = $shareMapper;
116
		$this->subscriptionMapper = $subscriptionMapper;
117
		$this->pollMapper = $pollMapper;
118
		$this->logMapper = $logMapper;
119
	}
120
121
122
	/**
123
	 * sendMail - Send eMail and evaluate recipient's mail address
124
	 * and displayname if $userId is a site user
125
	 * @param IEmailTemplate $emailTemplate
126
	 * @param String $userId
127
	 * @param String $emailAddress, ignored, when $userId is set
128
	 * @param String $displayName, ignored, when $userId is set
129
	 * @return String
130
	 */
131
132
	private function sendMail($emailTemplate, $emailAddress, $displayName) {
133
		if (!$emailAddress || !filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) {
134
			throw new \Exception('Invalid email address (' . $emailAddress . ')');
135
		}
136
137
		try {
138
			$message = $this->mailer->createMessage();
139
			$message->setTo([$emailAddress => $displayName]);
140
			$message->useTemplate($emailTemplate);
141
			$this->mailer->send($message);
142
143
			return null;
144
		} catch (\Exception $e) {
145
			\OC::$server->getLogger()->logException($e->getMessage(), ['app' => 'polls']);
146
			throw $e;
147
		}
148
	}
149
150
	/**
151
	 * @param integer $pollId
152
	 * @param string $userId
153
	 * @return string
154
	 */
155
	public function resolveEmailAddress($pollId, $userId) {
156
		if ($this->userManager->get($userId) instanceof IUser) {
157
			return \OC::$server->getConfig()->getUserValue($userId, 'settings', 'email');
158
		}
159
160
		// if $userId is no site user, eval via shares
161
		try {
162
			$share = $this->shareMapper->findByPollAndUser($pollId, $userId);
163
			if ($share->getEmailAddress()) {
164
				return $share->getEmailAddress();
165
			}
166
		} catch (\Exception $e) {
167
			// catch silently
168
		}
169
		return $userId;
170
	}
171
172
	/**
173
	 * @param string $token
174
	 */
175
	public function sendInvitation($token) {
176
		$share = $this->shareMapper->findByToken($token);
177
		$poll = $this->pollMapper->find($share->getPollId());
178
		$sentMails = [];
179
		$abortedMails = [];
180
181
		foreach ($share->getMembers() as $recipient) {
182
			//skip poll owner
183
			if ($recipient->getId() === $poll->getOwner()) {
184
				continue;
185
			}
186
187
			$emailTemplate = $this->generateInvitation($recipient, $poll, $share->getURL());
188
189
			try {
190
				$this->sendMail(
191
					$emailTemplate,
192
					$recipient->getEmailAddress(),
193
					$recipient->getDisplayName()
194
				);
195
				$share->setInvitationSent(time());
196
				$this->shareMapper->update($share);
197
				$sentMails[] = $recipient->getId();
198
			} catch (\Exception $e) {
199
				$abortedMails[] = $recipient->getId();
200
				\OC::$server->getLogger()->alert('Error sending Mail to ' . json_encode($recipient));
201
			}
202
		}
203
		return ['sentMails' => $sentMails, 'abortedMails' => $abortedMails];
204
	}
205
206
	public function sendNotifications() {
207
		$subscriptions = [];
208
		$log = $this->logMapper->findUnprocessedPolls();
209
210
		foreach ($log as $logItem) {
211
			$subscriptions = array_merge($subscriptions, $this->subscriptionMapper->findAllByPoll($logItem->getPollId()));
212
		}
213
214
		$log = $this->logMapper->findUnprocessed();
215
216
		foreach ($subscriptions as $subscription) {
217
			$poll = $this->pollMapper->find($subscription->getPollId());
218
219
			if ($this->userManager->get($subscription->getUserId()) instanceof IUser) {
220
				$recipient = new User($subscription->getUserId());
221
				$url = $this->urlGenerator->linkToRouteAbsolute(
222
					'polls.page.vote',
223
					['id' => $subscription->getPollId()]
224
				);
225
			} else {
226
				try {
227
					$share = $this->shareMapper->findByPollAndUser($subscription->getPollId(), $subscription->getUserId());
228
					$recipient = $share->getUserObject();
229
					$url = $share->getURL();
230
				} catch (\Exception $e) {
231
					continue;
232
				}
233
			}
234
235
			$emailTemplate = $this->generateNotification($recipient, $poll, $url, $log);
236
237
			try {
238
				$this->sendMail(
239
					$emailTemplate,
240
					$recipient->getEmailAddress(),
241
					$recipient->getDisplayName()
242
				);
243
			} catch (\Exception $e) {
244
				\OC::$server->getLogger()->alert('Error sending Mail to ' . $recipient->getId());
245
			}
246
		}
247
	}
248
249
	/**
250
	 * getLogString
251
	 * @param Log $logItem
252
	 * @param string $displayName
253
	 * @return string
254
	 */
255
256
	private function getLogString($logItem, $displayName) {
257
258
		if ($logItem->getMessage()) {
259
			return $logItem->getMessage();
260
		}
261
262
		switch ($logItem->getMessageId()) {
263
			case Log::MSG_ID_SETVOTE:
264
				return $this->trans->t('- %s voted.', [$displayName]);
265
			case Log::MSG_ID_UPDATEPOLL:
266
				return $this->trans->t('- Updated poll configuration. Please check your votes.');
267
			case Log::MSG_ID_DELETEPOLL:
268
				return $this->trans->t('- The poll got deleted.');
269
			case Log::MSG_ID_RESTOREPOLL:
270
				return $this->trans->t('- The poll got restored.');
271
			case Log::MSG_ID_EXPIREPOLL:
272
				return $this->trans->t('- The poll was closed.');
273
			case Log::MSG_ID_ADDOPTION:
274
				return $this->trans->t('- A vote option was added.');
275
			case Log::MSG_ID_DELETEOPTION:
276
				return $this->trans->t('- A vote option was removed.');
277
			default:
278
				return $logItem->getMessageId() . " (" . $displayName . ")";
279
		}
280
	}
281
282
	/**
283
	 * generateNotification
284
	 * @param UserGroupClass $recipient
285
	 * @param Poll $poll
286
	 * @return Object $emailTemplate
287
	 */
288
289
	private function generateNotification($recipient, $poll, $url, $log) {
290
		$owner = $poll->getOwnerUserObject();
291
		if ($recipient->getLanguage()) {
292
			$this->trans = $this->transFactory->get('polls', $recipient->getLanguage());
293
		} else {
294
			$this->trans = $this->transFactory->get('polls', $owner->getLanguage());
295
		}
296
		$emailTemplate = $this->mailer->createEMailTemplate('polls.Notification', [
297
			'title' => $poll->getTitle(),
298
			'link' => $url
299
		]);
300
301
		$emailTemplate->setSubject($this->trans->t('Polls App - New Activity'));
302
		$emailTemplate->addHeader();
303
		$emailTemplate->addHeading($this->trans->t('Polls App - New Activity'), false);
304
		$emailTemplate->addBodyText(str_replace(
305
			['{title}'],
306
			[$poll->getTitle()],
307
			$this->trans->t('"{title}" had recent activity: ')
308
		));
309
		foreach ($log as $logItem) {
310
			if ($logItem->getPollId() === $poll->getId()) {
311
				if ($poll->getAnonymous() || $poll->getShowResults() !== "always") {
312
					$displayName = $this->trans->t('A user');
313
				} elseif ($this->userManager->get($logItem->getUserId()) instanceof IUser) {
314
					$actor = new User($recipient->getUserId());
0 ignored issues
show
Bug introduced by
The method getUserId() does not exist on OCA\Polls\Model\UserGroupClass. Did you maybe mean getUser()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

314
					$actor = new User($recipient->/** @scrutinizer ignore-call */ getUserId());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
315
					$displayName = $actor->getDisplayName();
316
				} else {
317
					try {
318
						$share = $this->shareMapper->findByPollAndUser($poll->getId(), $logItem->getUserId());
319
						$displayName = $share->getUserObject()->getDisplayName();
320
					} catch (\Exception $e) {
321
						$displayName = $logItem->getUserId();
322
					}
323
				}
324
325
				$emailTemplate->addBodyText(getLogString($logItem, $displayName));
0 ignored issues
show
Bug introduced by
The function getLogString was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

325
				$emailTemplate->addBodyText(/** @scrutinizer ignore-call */ getLogString($logItem, $displayName));
Loading history...
326
			}
327
328
			$logItem->setProcessed(time());
329
			$this->logMapper->update($logItem);
330
		}
331
332
		$emailTemplate->addBodyButton(
333
			htmlspecialchars($this->trans->t('Go to poll')),
334
			$url,
335
			/** @scrutinizer ignore-type */ false
336
		);
337
		$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.'));
338
339
		return $emailTemplate;
340
	}
341
342
	/**
343
	 * generateInvitation
344
	 * @param UserGroupClass $recipient
345
	 * @param Poll $poll
346
	 * @return Object $emailTemplate
347
	 */
348
349
	private function generateInvitation($recipient, $poll, $url) {
350
		$owner = $poll->getOwnerUserObject();
351
		if ($recipient->getLanguage()) {
352
			$this->trans = $this->transFactory->get('polls', $recipient->getLanguage());
353
		} else {
354
			$this->trans = $this->transFactory->get('polls', $owner->getLanguage());
355
		}
356
357
		$emailTemplate = $this->mailer->createEMailTemplate('polls.Invitation', [
358
			'owner' => $owner->getDisplayName(),
359
			'title' => $poll->getTitle(),
360
			'link' => $url
361
		]);
362
363
		$emailTemplate->setSubject($this->trans->t('Poll invitation "%s"', $poll->getTitle()));
364
		$emailTemplate->addHeader();
365
		$emailTemplate->addHeading($this->trans->t('Poll invitation "%s"', $poll->getTitle()), false);
366
		$emailTemplate->addBodyText(str_replace(
367
				['{owner}', '{title}'],
368
				[$owner->getDisplayName(), $poll->getTitle()],
369
				$this->trans->t('{owner} invited you to take part in the poll "{title}"')
370
			));
371
		$emailTemplate->addBodyText($poll->getDescription());
372
		$emailTemplate->addBodyButton(
373
				htmlspecialchars($this->trans->t('Go to poll')),
374
				$url
375
			);
376
		$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: '));
377
		$emailTemplate->addBodyText($url);
378
		$emailTemplate->addBodyText($this->trans->t('Do not share this link with other people, because it is connected to your votes.'));
379
		$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.'));
380
381
		return $emailTemplate;
382
	}
383
}
384