Completed
Pull Request — master (#347)
by Maxence
01:46
created

FileSharingBroadcaster::getCloudsFromContact()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 8
Ratio 100 %

Importance

Changes 0
Metric Value
dl 8
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * Circles - Bring cloud-users closer together.
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
28
namespace OCA\Circles\Circles;
29
30
use daita\MySmallPhpTools\Traits\TArrayTools;
31
use Exception;
32
use OC;
33
use OC\Share20\Share;
34
use OCA\Circles\AppInfo\Application;
35
use OCA\Circles\Db\SharesRequest;
36
use OCA\Circles\Db\TokensRequest;
37
use OCA\Circles\Exceptions\TokenDoesNotExistException;
38
use OCA\Circles\IBroadcaster;
39
use OCA\Circles\Model\Circle;
40
use OCA\Circles\Model\Member;
41
use OCA\Circles\Model\SharesToken;
42
use OCA\Circles\Model\SharingFrame;
43
use OCA\Circles\Service\ConfigService;
44
use OCA\Circles\Service\MiscService;
45
use OCA\FederatedFileSharing\Notifications;
46
use OCP\AppFramework\QueryException;
47
use OCP\Defaults;
48
use OCP\Federation\ICloudFederationFactory;
49
use OCP\Federation\ICloudFederationProviderManager;
50
use OCP\Federation\ICloudIdManager;
51
use OCP\Files\IRootFolder;
52
use OCP\Files\NotFoundException;
53
use OCP\IL10N;
54
use OCP\ILogger;
55
use OCP\IURLGenerator;
56
use OCP\IUser;
57
use OCP\IUserManager;
58
use OCP\Mail\IEMailTemplate;
59
use OCP\Mail\IMailer;
60
use OCP\Share\Exceptions\IllegalIDChangeException;
61
use OCP\Share\IShare;
62
use OCP\Util;
63
64
65
class FileSharingBroadcaster implements IBroadcaster {
66
67
68
	/** @var bool */
69
	private $initiated = false;
70
71
	/** @var IL10N */
72
	private $l10n = null;
73
74
	/** @var IMailer */
75
	private $mailer;
76
77
	/** @var IRootFolder */
78
	private $rootFolder;
79
80
	/** @var IUserManager */
81
	private $userManager;
82
83
	/** @var ICloudFederationFactory */
84
	private $federationFactory;
85
86
	/** @var ICloudFederationProviderManager */
87
	private $federationProviderManager;
88
89
	/** @var ICloudIdManager */
90
	private $federationCloudIdManager;
91
92
	/** @var Notifications */
93
	private $federationNotifications;
94
95
	/** @var ILogger */
96
	private $logger;
97
98
	/** @var Defaults */
99
	private $defaults;
100
101
	/** @var IURLGenerator */
102
	private $urlGenerator;
103
104
	/** @var SharesRequest */
105
	private $sharesRequest;
106
107
	/** @var TokensRequest */
108
	private $tokensRequest;
109
110
	/** @var ConfigService */
111
	private $configService;
112
113
	/** @var MiscService */
114
	private $miscService;
115
116
	/** @var bool */
117
	private $federatedEnabled = false;
118
119
	/**
120
	 * {@inheritdoc}
121
	 */
122
	public function init() {
123
		if ($this->initiated) {
124
			return;
125
		}
126
127
		$this->initiated = true;
128
		$this->l10n = OC::$server->getL10N(Application::APP_NAME);
129
		$this->mailer = OC::$server->getMailer();
130
		$this->rootFolder = OC::$server->getLazyRootFolder();
131
		$this->userManager = OC::$server->getUserManager();
132
		$this->federationFactory = OC::$server->getCloudFederationFactory();
133
		$this->federationProviderManager = OC::$server->getCloudFederationProviderManager();
134
		$this->federationCloudIdManager = OC::$server->getCloudIdManager();
135
		$this->logger = OC::$server->getLogger();
136
		$this->urlGenerator = OC::$server->getURLGenerator();
137
		try {
138
			$this->defaults = OC::$server->query(Defaults::class);
139
			$this->sharesRequest = OC::$server->query(SharesRequest::class);
140
			$this->tokensRequest = OC::$server->query(TokensRequest::class);
141
			$this->configService = OC::$server->query(ConfigService::class);
142
			$this->miscService = OC::$server->query(MiscService::class);
143
		} catch (QueryException $e) {
0 ignored issues
show
Bug introduced by
The class OCP\AppFramework\QueryException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
144
			OC::$server->getLogger()
145
					   ->log(1, 'Circles: cannot init FileSharingBroadcaster - ' . $e->getMessage());
146
		}
147
148
		try {
149
			$this->federationNotifications =
150
				OC::$server->query(Notifications::class);
151
			$this->federatedEnabled = true;
152
		} catch (QueryException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
Bug introduced by
The class OCP\AppFramework\QueryException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
153
		}
154
155
	}
156
157
158
	/**
159
	 * {@inheritdoc}
160
	 */
161
	public function end() {
162
	}
163
164
165
	/**
166
	 * {@inheritdoc}
167
	 */
168
	public function createShareToCircle(SharingFrame $frame, Circle $circle) {
169
		if ($frame->is0Circle()) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !$frame->is0Circle();.
Loading history...
170
			return false;
171
		}
172
173
		return true;
174
	}
175
176
177
	/**
178
	 * {@inheritdoc}
179
	 */
180
	public function deleteShareToCircle(SharingFrame $frame, Circle $circle) {
181
		return true;
182
	}
183
184
185
	/**
186
	 * {@inheritdoc}
187
	 */
188
	public function editShareToCircle(SharingFrame $frame, Circle $circle) {
189
		return true;
190
	}
191
192
193
	/**
194
	 * {@inheritdoc}
195
	 * @throws IllegalIDChangeException
196
	 */
197
	public function createShareToMember(SharingFrame $frame, Member $member) {
198
		if (!$frame->is0Circle()) {
199
			return false;
200
		}
201
202
		$payload = $frame->getPayload();
203
		if (!key_exists('share', $payload)) {
204
			return false;
205
		}
206
207
		$share = $this->generateShare($payload['share']);
208
		if ($member->getType() === Member::TYPE_MAIL || $member->getType() === Member::TYPE_CONTACT) {
209
			try {
210
				$circle = $frame->getCircle();
211
212
				// federated shared in contact
213
				$clouds = $this->getCloudsFromContact($member->getUserId());
214
				if ($this->federatedEnabled && !empty($clouds)) {
215
					$sent = false;
216
					foreach ($clouds as $cloudId) {
217
						$sharesToken = $this->tokensRequest->generateTokenForMember($member, $share->getId());
218
						if ($this->sharedByFederated($circle, $share, $cloudId, $sharesToken)) {
219
							$sent = true;
220
						}
221
					}
222
223
					if ($sent) {
224
						return true;
225
					}
226
				}
227
228
				$password = '';
229
				if ($this->configService->enforcePasswordProtection()) {
230
					$password = $this->miscService->token(15);
231
				}
232
233
				$sharesToken = $this->tokensRequest->generateTokenForMember($member, $share->getId(), $password);
234
				$mails = [$member->getUserId()];
235
				if ($member->getType() === Member::TYPE_CONTACT) {
236
					$mails = $this->getMailsFromContact($member->getUserId());
237
				}
238
239
				foreach ($mails as $mail) {
240
					$this->sharedByMail($circle, $share, $mail, $sharesToken, $password);
241
				}
242
			} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
243
			}
244
		}
245
246
		return true;
247
	}
248
249
250
	/**
251
	 * {@inheritdoc}
252
	 */
253
	public function deleteShareToMember(SharingFrame $frame, Member $member) {
254
		return true;
255
	}
256
257
258
	/**
259
	 * {@inheritdoc}
260
	 */
261
	public function editShareToMember(SharingFrame $frame, Member $member) {
262
		return true;
263
	}
264
265
266
	/**
267
	 * @param Circle $circle
268
	 * @param Member $member
269
	 */
270
	public function sendMailAboutExistingShares(Circle $circle, Member $member) {
271
		if ($member->getType() !== Member::TYPE_MAIL && $member->getType() !== Member::TYPE_CONTACT
272
			&& $member->getContactId() !== '') {
273
			return;
274
		}
275
276
		$this->init();
277
278
		$allShares = $this->sharesRequest->getSharesForCircle($member->getCircleId());
279
		$knownShares = array_map(
280
			function(SharesToken $shareToken) {
281
				return $shareToken->getShareId();
282
			},
283
			$this->tokensRequest->getTokensFromMember($member)
284
		);
285
286
		$unknownShares = [];
287
		foreach ($allShares as $share) {
288
			if (!in_array($share['id'], $knownShares)) {
289
				$unknownShares[] = $share;
290
			}
291
		}
292
293
		$author = $circle->getViewer()
294
						 ->getUserId();
295
296
		$recipient = $member->getUserId();
297
		if ($member->getType() === Member::TYPE_CONTACT) {
298
			$data = MiscService::getContactData($member->getUserId());
299
			if (!array_key_exists('EMAIL', $data)) {
300
				return;
301
			}
302
303
			$emails = $data['EMAIL'];
304
			if (empty($emails)) {
305
				return;
306
			}
307
308
			$recipient = $emails[0];
309
		}
310
311
		$this->sendMailExitingShares(
312
			$unknownShares, MiscService::getDisplay($author, Member::TYPE_USER), $member, $recipient,
313
			$circle->getName()
314
		);
315
	}
316
317
318
	/**
319
	 * recreate the share from the JSON payload.
320
	 *
321
	 * @param array $data
322
	 *
323
	 * @return IShare
324
	 * @throws IllegalIDChangeException
325
	 */
326
	private function generateShare($data): IShare {
327
		$this->logger->log(0, 'Regenerate shares from payload: ' . json_encode($data));
328
329
		$share = new Share($this->rootFolder, $this->userManager);
330
		$share->setId($data['id']);
331
		$share->setSharedBy($data['sharedBy']);
332
		$share->setSharedWith($data['sharedWith']);
333
		$share->setNodeId($data['nodeId']);
334
		$share->setShareOwner($data['shareOwner']);
335
		$share->setPermissions($data['permissions']);
336
		$share->setToken($data['token']);
337
		$share->setPassword($data['password']);
338
339
		return $share;
340
	}
341
342
343
	/**
344
	 * @param Circle $circle
345
	 * @param IShare $share
346
	 * @param string $address
347
	 * @param string $token
0 ignored issues
show
Documentation introduced by
Should the type for parameter $token not be SharesToken?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
348
	 *
349
	 * @return bool
350
	 */
351
	public function sharedByFederated(Circle $circle, IShare $share, string $address, SharesToken $token
0 ignored issues
show
Unused Code introduced by
The parameter $circle is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
352
	): bool {
353
		try {
354
			$cloudId = $this->federationCloudIdManager->resolveCloudId($address);
355
356
			$localUrl = $this->urlGenerator->getAbsoluteURL('/');
357
			$sharedByFederatedId = $share->getSharedBy();
358
			if ($this->userManager->userExists($sharedByFederatedId)) {
359
				$cloudId = $this->federationCloudIdManager->getCloudId($sharedByFederatedId, $localUrl);
360
				$sharedByFederatedId = $cloudId->getId();
361
			}
362
			$ownerCloudId = $this->federationCloudIdManager->getCloudId($share->getShareOwner(), $localUrl);
363
364
			$send = $this->federationNotifications->sendRemoteShare(
365
				$token->getToken(),
366
				$address,
367
				$share->getNode()
368
					  ->getName(),
369
				$share->getId(),
370
				$share->getShareOwner(),
371
				$ownerCloudId->getId(),
372
				$share->getSharedBy(),
373
				$sharedByFederatedId,
374
				Share::TYPE_USER
375
			);
376
377
			return $send;
378
		} catch (\Exception $e) {
379
			$this->logger->logException(
380
				$e, [
381
					  'message' => 'Failed to notify remote server of circles-federated share',
382
					  'level'   => ILogger::ERROR,
383
					  'app'     => 'circles',
384
				  ]
385
			);
386
		}
387
388
		return false;
389
	}
390
391
392
	/**
393
	 * @param Circle $circle
394
	 * @param IShare $share
395
	 * @param string $email
396
	 * @param SharesToken $sharesToken
397
	 * @param string $password
398
	 */
399
	private function sharedByMail(
400
		Circle $circle, IShare $share, string $email, SharesToken $sharesToken, string $password
401
	) {
402
		// genelink
403
		$link = $this->urlGenerator->linkToRouteAbsolute(
404
			'files_sharing.sharecontroller.showShare',
405
			['token' => $sharesToken->getToken()]
406
		);
407
408
		try {
409
			$this->sendMail(
410
				$share->getNode()
411
					  ->getName(), $link,
412
				MiscService::getDisplay($share->getSharedBy(), Member::TYPE_USER),
413
				$circle->getName(), $email
414
			);
415
			$this->sendPasswordByMail(
416
				$share, MiscService::getDisplay($share->getSharedBy(), Member::TYPE_USER),
417
				$email, $password
418
			);
419
		} catch (Exception $e) {
420
			OC::$server->getLogger()
421
					   ->log(1, 'Circles::sharedByMail - mail were not sent: ' . $e->getMessage());
422
		}
423
	}
424
425
426
	/**
427
	 * @param $fileName
428
	 * @param string $link
429
	 * @param string $author
430
	 * @param $circleName
431
	 * @param string $email
432
	 *
433
	 * @throws Exception
434
	 */
435
	protected function sendMail($fileName, $link, $author, $circleName, $email) {
436
		$message = $this->mailer->createMessage();
437
438
		$this->logger->log(
439
			0, "Sending mail to circle '" . $circleName . "': " . $email . ' file: ' . $fileName
440
			   . ' - link: ' . $link
441
		);
442
443
		$subject = $this->l10n->t('%s shared »%s« with you.', [$author, $fileName]);
444
		$text = $this->l10n->t('%s shared »%s« with \'%s\'.', [$author, $fileName, $circleName]);
445
446
		$emailTemplate =
447
			$this->generateEmailTemplate($subject, $text, $fileName, $link, $author, $circleName);
448
449
		$instanceName = $this->defaults->getName();
450
		$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]);
451
452
		$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]);
453
		$message->setSubject($subject);
454
		$message->setPlainBody($emailTemplate->renderText());
455
		$message->setHtmlBody($emailTemplate->renderHtml());
456
		$message->setTo([$email]);
457
458
		$this->mailer->send($message);
459
	}
460
461
462
	/**
463
	 * @param IShare $share
464
	 * @param string $circleName
465
	 * @param string $email
466
	 *
467
	 * @param $password
468
	 *
469
	 * @throws NotFoundException
470
	 * @throws Exception
471
	 */
472
	protected function sendPasswordByMail(IShare $share, $circleName, $email, $password) {
473
		if (!$this->configService->sendPasswordByMail() || $password === '') {
474
			return;
475
		}
476
477
		$message = $this->mailer->createMessage();
478
479
		$this->logger->log(0, "Sending password mail to circle '" . $circleName . "': " . $email);
480
481
		$filename = $share->getNode()
482
						  ->getName();
483
		$initiator = $share->getSharedBy();
484
		$shareWith = $share->getSharedWith();
485
486
		$initiatorUser = $this->userManager->get($initiator);
487
		$initiatorDisplayName =
488
			($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator;
0 ignored issues
show
Bug introduced by
The class OCP\IUser does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
489
		$initiatorEmailAddress =
490
			($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null;
0 ignored issues
show
Bug introduced by
The class OCP\IUser does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
491
492
		$plainBodyPart = $this->l10n->t(
493
			"%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n",
494
			[$initiatorDisplayName, $filename]
495
		);
496
		$htmlBodyPart = $this->l10n->t(
497
			'%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.',
498
			[$initiatorDisplayName, $filename]
499
		);
500
501
		$emailTemplate = $this->mailer->createEMailTemplate(
502
			'sharebymail.RecipientPasswordNotification', [
503
														   'filename'       => $filename,
504
														   'password'       => $password,
505
														   'initiator'      => $initiatorDisplayName,
506
														   'initiatorEmail' => $initiatorEmailAddress,
507
														   'shareWith'      => $shareWith,
508
													   ]
509
		);
510
511
		$emailTemplate->setSubject(
512
			$this->l10n->t(
513
				'Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName]
514
			)
515
		);
516
		$emailTemplate->addHeader();
517
		$emailTemplate->addHeading($this->l10n->t('Password to access »%s«', [$filename]), false);
518
		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
519
		$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:'));
520
		$emailTemplate->addBodyText($password);
521
522
		// The "From" contains the sharers name
523
		$instanceName = $this->defaults->getName();
524
		$senderName = $this->l10n->t(
525
			'%1$s via %2$s',
526
			[
527
				$initiatorDisplayName,
528
				$instanceName
529
			]
530
		);
531
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
532 View Code Duplication
		if ($initiatorEmailAddress !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
533
			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
534
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
535
		} else {
536
			$emailTemplate->addFooter();
537
		}
538
539
		$message->setTo([$email]);
540
		$message->useTemplate($emailTemplate);
541
		$this->mailer->send($message);
542
	}
543
544
545
	/**
546
	 * @param $subject
547
	 * @param $text
548
	 * @param $fileName
549
	 * @param $link
550
	 * @param string $author
551
	 * @param string $circleName
552
	 *
553
	 * @return IEMailTemplate
554
	 */
555
	private function generateEmailTemplate($subject, $text, $fileName, $link, $author, $circleName
556
	) {
557
		$emailTemplate = $this->mailer->createEMailTemplate(
558
			'circles.ShareNotification', [
559
										   'fileName'   => $fileName,
560
										   'fileLink'   => $link,
561
										   'author'     => $author,
562
										   'circleName' => $circleName,
563
									   ]
564
		);
565
566
		$emailTemplate->addHeader();
567
		$emailTemplate->addHeading($subject, false);
568
		$emailTemplate->addBodyText(
569
			htmlspecialchars($text) . '<br>' . htmlspecialchars(
570
				$this->l10n->t('Click the button below to open it.')
571
			), $text
572
		);
573
		$emailTemplate->addBodyButton(
574
			$this->l10n->t('Open »%s«', [htmlspecialchars($fileName)]), $link
575
		);
576
577
		return $emailTemplate;
578
	}
579
580
581
	/**
582
	 * @param array $unknownShares
583
	 * @param string $author
584
	 * @param Member $member
585
	 * @param string $recipient
586
	 * @param string $circleName
587
	 */
588
	public function sendMailExitingShares(
589
		array $unknownShares, $author, Member $member, $recipient, $circleName
590
	) {
591
		$data = [];
592
593
		$password = '';
594
		if ($this->configService->enforcePasswordProtection()) {
595
			$password = $this->miscService->token(15);
596
		}
597
598
		foreach ($unknownShares as $share) {
599
			try {
600
				$data[] = $this->getMailLinkFromShare($share, $member, $password);
601
			} catch (TokenDoesNotExistException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
602
			}
603
		}
604
605
		if (sizeof($data) === 0) {
606
			return;
607
		}
608
609
		try {
610
			$template = $this->generateMailExitingShares($author, $circleName);
611
			$this->fillMailExistingShares($template, $data);
612
			$this->sendMailExistingShares($template, $author, $recipient);
613
			$this->sendPasswordExistingShares($author, $recipient, $password);
614
		} catch (Exception $e) {
615
			$this->logger->log(2, 'Failed to send mail about existing share ' . $e->getMessage());
616
		}
617
	}
618
619
620
	/**
621
	 * @param $author
622
	 * @param string $email
623
	 *
624
	 * @param $password
625
	 *
626
	 * @throws Exception
627
	 */
628
	protected function sendPasswordExistingShares($author, $email, $password) {
629
		if (!$this->configService->sendPasswordByMail() || $password === '') {
630
			return;
631
		}
632
633
		$message = $this->mailer->createMessage();
634
635
		$authorUser = $this->userManager->get($author);
636
		$authorName = ($authorUser instanceof IUser) ? $authorUser->getDisplayName() : $author;
0 ignored issues
show
Bug introduced by
The class OCP\IUser does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
637
		$authorEmail = ($authorUser instanceof IUser) ? $authorUser->getEMailAddress() : null;
0 ignored issues
show
Bug introduced by
The class OCP\IUser does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
638
639
		$this->logger->log(0, "Sending password mail about existing files to '" . $email . "'");
640
641
		$plainBodyPart = $this->l10n->t(
642
			"%1\$s shared multiple files with you.\nYou should have already received a separate mail with a link to access them.\n",
643
			[$authorName]
644
		);
645
		$htmlBodyPart = $this->l10n->t(
646
			'%1$s shared multiple files with you. You should have already received a separate mail with a link to access them.',
647
			[$authorName]
648
		);
649
650
		$emailTemplate = $this->mailer->createEMailTemplate(
651
			'sharebymail.RecipientPasswordNotification', [
652
														   'password' => $password,
653
														   'author'   => $author
654
													   ]
655
		);
656
657
		$emailTemplate->setSubject(
658
			$this->l10n->t(
659
				'Password to access files shared to you by %1$s', [$authorName]
660
			)
661
		);
662
		$emailTemplate->addHeader();
663
		$emailTemplate->addHeading($this->l10n->t('Password to access files'), false);
664
		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
665
		$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:'));
666
		$emailTemplate->addBodyText($password);
667
668
		// The "From" contains the sharers name
669
		$instanceName = $this->defaults->getName();
670
		$senderName = $this->l10n->t(
671
			'%1$s via %2$s',
672
			[
673
				$authorName,
674
				$instanceName
675
			]
676
		);
677
678
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
679 View Code Duplication
		if ($authorEmail !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
680
			$message->setReplyTo([$authorEmail => $authorName]);
681
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
682
		} else {
683
			$emailTemplate->addFooter();
684
		}
685
686
		$message->setTo([$email]);
687
		$message->useTemplate($emailTemplate);
688
		$this->mailer->send($message);
689
	}
690
691
	/**
692
	 * @param array $share
693
	 * @param Member $member
694
	 * @param string $password
695
	 *
696
	 * @return array
697
	 * @throws TokenDoesNotExistException
698
	 */
699
	private function getMailLinkFromShare(array $share, Member $member, string $password = '') {
700
		$sharesToken = $this->tokensRequest->generateTokenForMember($member, $share['id'], $password);
701
		$link = $this->urlGenerator->linkToRouteAbsolute(
702
			'files_sharing.sharecontroller.showShare',
703
			['token' => $sharesToken->getToken()]
704
		);
705
		$author = $share['uid_initiator'];
706
707
		$filename = basename($share['file_target']);
708
709
		return [
710
			'author'   => $author,
711
			'link'     => $link,
712
			'filename' => $filename
713
		];
714
	}
715
716
717
	/**
718
	 * @param $author
719
	 * @param string $circleName
720
	 *
721
	 * @return IEMailTemplate
722
	 * @throws Exception
723
	 */
724
	protected function generateMailExitingShares($author, $circleName) {
725
		$this->logger->log(
726
			0, "Generating mail about existing share mail from '" . $author . "' in "
727
			   . $circleName
728
		);
729
730
		$emailTemplate = $this->mailer->createEMailTemplate('circles.ExistingShareNotification', []);
731
		$emailTemplate->addHeader();
732
733
		$text = $this->l10n->t('%s shared multiple files with \'%s\'.', [$author, $circleName]);
734
		$emailTemplate->addBodyText(htmlspecialchars($text), $text);
735
736
		return $emailTemplate;
737
	}
738
739
740
	/**
741
	 * @param IEMailTemplate $emailTemplate
742
	 * @param array $data
743
	 */
744
	protected function fillMailExistingShares(IEMailTemplate $emailTemplate, array $data) {
745
		foreach ($data as $item) {
746
//			$text = $this->l10n->t('%s shared »%s« with you.', [$item['author'], $item['filename']]);
747
//			$emailTemplate->addBodyText(
748
//				htmlspecialchars($text) . '<br>' . htmlspecialchars(
749
//					$this->l10n->t('Click the button below to open it.')
750
//				), $text
751
//			);
752
			$emailTemplate->addBodyButton(
753
				$this->l10n->t('Open »%s«', [htmlspecialchars($item['filename'])]), $item['link']
754
			);
755
		}
756
	}
757
758
759
	/**
760
	 * @param IEMailTemplate $emailTemplate
761
	 * @param $author
762
	 * @param $recipient
763
	 *
764
	 * @throws Exception
765
	 */
766
	protected function sendMailExistingShares(IEMailTemplate $emailTemplate, $author, $recipient) {
767
		$subject = $this->l10n->t('%s shared multiple files with you.', [$author]);
768
//		$emailTemplate->addHeading($subject, false);
769
770
		$instanceName = $this->defaults->getName();
771
		$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]);
772
773
		$message = $this->mailer->createMessage();
774
775
		$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]);
776
		$message->setSubject($subject);
777
		$message->setPlainBody($emailTemplate->renderText());
778
		$message->setHtmlBody($emailTemplate->renderHtml());
779
		$message->setTo([$recipient]);
780
781
		$this->mailer->send($message);
782
	}
783
784
785
	/**
786
	 * @param string $contactId
787
	 *
788
	 * @return array
789
	 */
790 View Code Duplication
	private function getCloudsFromContact(string $contactId): array {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
791
		$contact = MiscService::getContactData($contactId);
792
		if (!key_exists('CLOUD', $contact)) {
793
			return [];
794
		}
795
796
		return $contact['CLOUD'];
797
	}
798
799
	/**
800
	 * @param string $contactId
801
	 *
802
	 * @return array
803
	 */
804 View Code Duplication
	private function getMailsFromContact(string $contactId): array {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
805
		$contact = MiscService::getContactData($contactId);
806
		if (!key_exists('EMAIL', $contact)) {
807
			return [];
808
		}
809
810
		return $contact['EMAIL'];
811
	}
812
813
}
814