Completed
Pull Request — master (#347)
by Maxence
02:26
created

FileSharingBroadcaster::init()   A

Complexity

Conditions 4
Paths 13

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 34
rs 9.376
c 0
b 0
f 0
cc 4
nc 13
nop 0
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 Exception;
31
use OC;
32
use OC\Share20\Share;
33
use OCA\Circles\AppInfo\Application;
34
use OCA\Circles\Db\SharesRequest;
35
use OCA\Circles\Db\TokensRequest;
36
use OCA\Circles\Exceptions\TokenDoesNotExistException;
37
use OCA\Circles\IBroadcaster;
38
use OCA\Circles\Model\Circle;
39
use OCA\Circles\Model\Member;
40
use OCA\Circles\Model\SharesToken;
41
use OCA\Circles\Model\SharingFrame;
42
use OCA\Circles\Service\ConfigService;
43
use OCA\Circles\Service\MiscService;
44
use OCA\FederatedFileSharing\Notifications;
45
use OCP\AppFramework\QueryException;
46
use OCP\Defaults;
47
use OCP\Federation\ICloudFederationFactory;
48
use OCP\Federation\ICloudFederationProviderManager;
49
use OCP\Federation\ICloudIdManager;
50
use OCP\Files\IRootFolder;
51
use OCP\Files\NotFoundException;
52
use OCP\IL10N;
53
use OCP\ILogger;
54
use OCP\IURLGenerator;
55
use OCP\IUser;
56
use OCP\IUserManager;
57
use OCP\Mail\IEMailTemplate;
58
use OCP\Mail\IMailer;
59
use OCP\Share\Exceptions\IllegalIDChangeException;
60
use OCP\Share\IShare;
61
use OCP\Util;
62
63
64
class FileSharingBroadcaster implements IBroadcaster {
65
66
67
	/** @var bool */
68
	private $initiated = false;
69
70
	/** @var IL10N */
71
	private $l10n = null;
72
73
	/** @var IMailer */
74
	private $mailer;
75
76
	/** @var IRootFolder */
77
	private $rootFolder;
78
79
	/** @var IUserManager */
80
	private $userManager;
81
82
	/** @var ICloudFederationFactory */
83
	private $federationFactory;
84
85
	/** @var ICloudFederationProviderManager */
86
	private $federationProviderManager;
87
88
	/** @var ICloudIdManager */
89
	private $federationCloudIdManager;
90
91
	/** @var Notifications */
92
	private $federationNotifications;
93
94
	/** @var ILogger */
95
	private $logger;
96
97
	/** @var Defaults */
98
	private $defaults;
99
100
	/** @var IURLGenerator */
101
	private $urlGenerator;
102
103
	/** @var SharesRequest */
104
	private $sharesRequest;
105
106
	/** @var TokensRequest */
107
	private $tokensRequest;
108
109
	/** @var ConfigService */
110
	private $configService;
111
112
	/** @var MiscService */
113
	private $miscService;
114
115
	/** @var bool */
116
	private $federatedEnabled = false;
117
118
	/**
119
	 * {@inheritdoc}
120
	 */
121
	public function init() {
122
		if ($this->initiated) {
123
			return;
124
		}
125
126
		$this->initiated = true;
127
		$this->l10n = OC::$server->getL10N(Application::APP_NAME);
128
		$this->mailer = OC::$server->getMailer();
129
		$this->rootFolder = OC::$server->getLazyRootFolder();
130
		$this->userManager = OC::$server->getUserManager();
131
		$this->federationFactory = OC::$server->getCloudFederationFactory();
132
		$this->federationProviderManager = OC::$server->getCloudFederationProviderManager();
133
		$this->federationCloudIdManager = OC::$server->getCloudIdManager();
134
		$this->logger = OC::$server->getLogger();
135
		$this->urlGenerator = OC::$server->getURLGenerator();
136
		try {
137
			$this->defaults = OC::$server->query(Defaults::class);
138
			$this->sharesRequest = OC::$server->query(SharesRequest::class);
139
			$this->tokensRequest = OC::$server->query(TokensRequest::class);
140
			$this->configService = OC::$server->query(ConfigService::class);
141
			$this->miscService = OC::$server->query(MiscService::class);
142
		} 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...
143
			OC::$server->getLogger()
144
					   ->log(1, 'Circles: cannot init FileSharingBroadcaster - ' . $e->getMessage());
145
		}
146
147
		try {
148
			$this->federationNotifications =
149
				OC::$server->query(Notifications::class);
150
			$this->federatedEnabled = true;
151
		} 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...
152
		}
153
154
	}
155
156
157
	/**
158
	 * {@inheritdoc}
159
	 */
160
	public function end() {
161
	}
162
163
164
	/**
165
	 * {@inheritdoc}
166
	 */
167
	public function createShareToCircle(SharingFrame $frame, Circle $circle) {
168
		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...
169
			return false;
170
		}
171
172
		return true;
173
	}
174
175
176
	/**
177
	 * {@inheritdoc}
178
	 */
179
	public function deleteShareToCircle(SharingFrame $frame, Circle $circle) {
180
		return true;
181
	}
182
183
184
	/**
185
	 * {@inheritdoc}
186
	 */
187
	public function editShareToCircle(SharingFrame $frame, Circle $circle) {
188
		return true;
189
	}
190
191
192
	/**
193
	 * {@inheritdoc}
194
	 * @throws IllegalIDChangeException
195
	 */
196
	public function createShareToMember(SharingFrame $frame, Member $member) {
197
		if (!$frame->is0Circle()) {
198
			return false;
199
		}
200
201
		$payload = $frame->getPayload();
202
		if (!key_exists('share', $payload)) {
203
			return false;
204
		}
205
206
		$share = $this->generateShare($payload['share']);
207
		if ($member->getType() === Member::TYPE_MAIL || $member->getType() === Member::TYPE_CONTACT) {
208
			try {
209
				$circle = $frame->getCircle();
210
211
				// federated shared in contact
212
				$clouds = $this->getCloudsFromContact($member->getUserId());
213
				if ($this->federatedEnabled && !empty($clouds)) {
214
					$sent = false;
215
					foreach ($clouds as $cloudId) {
216
						$sharesToken = $this->tokensRequest->generateTokenForMember($member, $share->getId());
217
						if ($this->sharedByFederated($circle, $share, $cloudId, $sharesToken)) {
218
							$sent = true;
219
						}
220
					}
221
222
					if ($sent) {
223
						return true;
224
					}
225
				}
226
227
				$password = '';
228
				if ($this->configService->enforcePasswordProtection()) {
229
					$password = $this->miscService->token(15);
230
				}
231
232
				$sharesToken = $this->tokensRequest->generateTokenForMember($member, $share->getId());
233
				$mails = [$member->getUserId()];
234
				if ($member->getType() === Member::TYPE_CONTACT) {
235
					$mails = $this->getMailsFromContact($member->getUserId());
236
				}
237
238
				foreach ($mails as $mail) {
239
					$this->sharedByMail($circle, $share, $mail, $sharesToken, $password);
0 ignored issues
show
Unused Code introduced by
The call to FileSharingBroadcaster::sharedByMail() has too many arguments starting with $password.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
240
				}
241
			} catch (Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
242
			}
243
		}
244
245
		return true;
246
	}
247
248
249
	/**
250
	 * {@inheritdoc}
251
	 */
252
	public function deleteShareToMember(SharingFrame $frame, Member $member) {
253
		return true;
254
	}
255
256
257
	/**
258
	 * {@inheritdoc}
259
	 */
260
	public function editShareToMember(SharingFrame $frame, Member $member) {
261
		return true;
262
	}
263
264
265
	/**
266
	 * @param Circle $circle
267
	 * @param Member $member
268
	 */
269
	public function sendMailAboutExistingShares(Circle $circle, Member $member) {
270
		$this->init();
271
		if ($this->configService->getAppValue(ConfigService::CIRCLES_CONTACT_BACKEND) === '1') {
272
			return;
273
		}
274
275
		if ($member->getType() !== Member::TYPE_MAIL && $member->getType() !== Member::TYPE_CONTACT) {
276
			return;
277
		}
278
279
		$allShares = $this->sharesRequest->getSharesForCircle($member->getCircleId());
280
		$knownShares = array_map(
281
			function(SharesToken $shareToken) {
282
				return $shareToken->getShareId();
283
			},
284
			$this->tokensRequest->getTokensFromMember($member)
285
		);
286
287
		$unknownShares = [];
288
		foreach ($allShares as $share) {
289
			if (!in_array($share['id'], $knownShares)) {
290
				$unknownShares[] = $share;
291
			}
292
		}
293
294
		$author = $circle->getViewer()
295
						 ->getUserId();
296
297
		$recipient = $member->getUserId();
0 ignored issues
show
Unused Code introduced by
$recipient is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
298
		if ($member->getType() === Member::TYPE_CONTACT) {
299
			$recipient = MiscService::getContactData($member->getUserId());
300
			// TODO: CHECK THIS CHECK THIS CHECK TINS :: Get email from Contact
301
			$this->miscService->log('___ RECIPIENT !! ' . json_encode($recipient));
302
		}
303
304
		$recipient = $member->getUserId();
305
		$this->sendMailExitingShares(
306
			$unknownShares, MiscService::getDisplay($author, Member::TYPE_USER), $member, $recipient,
307
			$circle->getName()
308
		);
309
	}
310
311
312
	/**
313
	 * recreate the share from the JSON payload.
314
	 *
315
	 * @param array $data
316
	 *
317
	 * @return IShare
318
	 * @throws IllegalIDChangeException
319
	 */
320
	private function generateShare($data): IShare {
321
		$this->logger->log(0, 'Regenerate shares from payload: ' . json_encode($data));
322
323
		$share = new Share($this->rootFolder, $this->userManager);
324
		$share->setId($data['id']);
325
		$share->setSharedBy($data['sharedBy']);
326
		$share->setSharedWith($data['sharedWith']);
327
		$share->setNodeId($data['nodeId']);
328
		$share->setShareOwner($data['shareOwner']);
329
		$share->setPermissions($data['permissions']);
330
		$share->setToken($data['token']);
331
		$share->setPassword($data['password']);
332
333
		return $share;
334
	}
335
336
337
	/**
338
	 * @param Circle $circle
339
	 * @param IShare $share
340
	 * @param string $address
341
	 * @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...
342
	 *
343
	 * @return bool
344
	 */
345
	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...
346
	): bool {
347
		try {
348
			$cloudId = $this->federationCloudIdManager->resolveCloudId($address);
349
350
			$localUrl = $this->urlGenerator->getAbsoluteURL('/');
351
			$sharedByFederatedId = $share->getSharedBy();
352
			if ($this->userManager->userExists($sharedByFederatedId)) {
353
				$cloudId = $this->federationCloudIdManager->getCloudId($sharedByFederatedId, $localUrl);
354
				$sharedByFederatedId = $cloudId->getId();
355
			}
356
			$ownerCloudId = $this->federationCloudIdManager->getCloudId($share->getShareOwner(), $localUrl);
357
358
			$send = $this->federationNotifications->sendRemoteShare(
359
				$token->getToken(),
360
				$address,
361
				$share->getNode()
362
					  ->getName(),
363
				$share->getId(),
364
				$share->getShareOwner(),
365
				$ownerCloudId->getId(),
366
				$share->getSharedBy(),
367
				$sharedByFederatedId,
368
				Share::TYPE_USER
369
			);
370
371
			return $send;
372
		} catch (\Exception $e) {
373
			$this->logger->logException(
374
				$e, [
375
					  'message' => 'Failed to notify remote server of circles-federated share',
376
					  'level'   => ILogger::ERROR,
377
					  'app'     => 'circles',
378
				  ]
379
			);
380
		}
381
382
		return false;
383
	}
384
385
386
	/**
387
	 * @param Circle $circle
388
	 * @param IShare $share
389
	 * @param string $email
390
	 * @param SharesToken $sharesToken
391
	 */
392
	private function sharedByMail(Circle $circle, IShare $share, $email, SharesToken $sharesToken) {
393
		// genelink
394
		$link = $this->urlGenerator->linkToRouteAbsolute(
395
			'files_sharing.sharecontroller.showShare',
396
			['token' => $sharesToken->getToken()]
397
		);
398
399
		try {
400
			$this->sendMail(
401
				$share->getNode()
402
					  ->getName(), $link,
403
				MiscService::getDisplay($share->getSharedBy(), Member::TYPE_USER),
404
				$circle->getName(), $email
405
			);
406
			$this->sendPasswordByMail(
407
				$share, MiscService::getDisplay($share->getSharedBy(), Member::TYPE_USER),
408
				$email, $sharesToken->getOrigPassword()
409
			);
410
		} catch (Exception $e) {
411
			OC::$server->getLogger()
412
					   ->log(1, 'Circles::sharedByMail - mail were not sent: ' . $e->getMessage());
413
		}
414
	}
415
416
417
	/**
418
	 * @param $fileName
419
	 * @param string $link
420
	 * @param string $author
421
	 * @param $circleName
422
	 * @param string $email
423
	 *
424
	 * @throws Exception
425
	 */
426
	protected function sendMail($fileName, $link, $author, $circleName, $email) {
427
		$message = $this->mailer->createMessage();
428
429
		$this->logger->log(
430
			0, "Sending mail to circle '" . $circleName . "': " . $email . ' file: ' . $fileName
431
			   . ' - link: ' . $link
432
		);
433
434
		$subject = $this->l10n->t('%s shared »%s« with you.', [$author, $fileName]);
435
		$text = $this->l10n->t('%s shared »%s« with \'%s\'.', [$author, $fileName, $circleName]);
436
437
		$emailTemplate =
438
			$this->generateEmailTemplate($subject, $text, $fileName, $link, $author, $circleName);
439
440
		$instanceName = $this->defaults->getName();
441
		$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]);
442
443
		$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]);
444
		$message->setSubject($subject);
445
		$message->setPlainBody($emailTemplate->renderText());
446
		$message->setHtmlBody($emailTemplate->renderHtml());
447
		$message->setTo([$email]);
448
449
		$this->mailer->send($message);
450
	}
451
452
453
	/**
454
	 * @param IShare $share
455
	 * @param string $circleName
456
	 * @param string $email
457
	 *
458
	 * @param $password
459
	 *
460
	 * @throws NotFoundException
461
	 * @throws Exception
462
	 */
463
	protected function sendPasswordByMail(IShare $share, $circleName, $email, $password) {
464
		if (!$this->configService->sendPasswordByMail() || $password === '') {
465
			return;
466
		}
467
468
		$message = $this->mailer->createMessage();
469
470
		$this->logger->log(0, "Sending password mail to circle '" . $circleName . "': " . $email);
471
472
		$filename = $share->getNode()
473
						  ->getName();
474
		$initiator = $share->getSharedBy();
475
		$shareWith = $share->getSharedWith();
476
477
		$initiatorUser = $this->userManager->get($initiator);
478
		$initiatorDisplayName =
479
			($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...
480
		$initiatorEmailAddress =
481
			($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...
482
483
		$plainBodyPart = $this->l10n->t(
484
			"%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n",
485
			[$initiatorDisplayName, $filename]
486
		);
487
		$htmlBodyPart = $this->l10n->t(
488
			'%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.',
489
			[$initiatorDisplayName, $filename]
490
		);
491
492
		$emailTemplate = $this->mailer->createEMailTemplate(
493
			'sharebymail.RecipientPasswordNotification', [
494
														   'filename'       => $filename,
495
														   'password'       => $password,
496
														   'initiator'      => $initiatorDisplayName,
497
														   'initiatorEmail' => $initiatorEmailAddress,
498
														   'shareWith'      => $shareWith,
499
													   ]
500
		);
501
502
		$emailTemplate->setSubject(
503
			$this->l10n->t(
504
				'Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName]
505
			)
506
		);
507
		$emailTemplate->addHeader();
508
		$emailTemplate->addHeading($this->l10n->t('Password to access »%s«', [$filename]), false);
509
		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
510
		$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:'));
511
		$emailTemplate->addBodyText($password);
512
513
		// The "From" contains the sharers name
514
		$instanceName = $this->defaults->getName();
515
		$senderName = $this->l10n->t(
516
			'%1$s via %2$s',
517
			[
518
				$initiatorDisplayName,
519
				$instanceName
520
			]
521
		);
522
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
523 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...
524
			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
525
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
526
		} else {
527
			$emailTemplate->addFooter();
528
		}
529
530
		$message->setTo([$email]);
531
		$message->useTemplate($emailTemplate);
532
		$this->mailer->send($message);
533
	}
534
535
536
	/**
537
	 * @param $subject
538
	 * @param $text
539
	 * @param $fileName
540
	 * @param $link
541
	 * @param string $author
542
	 * @param string $circleName
543
	 *
544
	 * @return IEMailTemplate
545
	 */
546
	private function generateEmailTemplate($subject, $text, $fileName, $link, $author, $circleName
547
	) {
548
		$emailTemplate = $this->mailer->createEMailTemplate(
549
			'circles.ShareNotification', [
550
										   'fileName'   => $fileName,
551
										   'fileLink'   => $link,
552
										   'author'     => $author,
553
										   'circleName' => $circleName,
554
									   ]
555
		);
556
557
		$emailTemplate->addHeader();
558
		$emailTemplate->addHeading($subject, false);
559
		$emailTemplate->addBodyText(
560
			htmlspecialchars($text) . '<br>' . htmlspecialchars(
561
				$this->l10n->t('Click the button below to open it.')
562
			), $text
563
		);
564
		$emailTemplate->addBodyButton(
565
			$this->l10n->t('Open »%s«', [htmlspecialchars($fileName)]), $link
566
		);
567
568
		return $emailTemplate;
569
	}
570
571
572
	/**
573
	 * @param array $unknownShares
574
	 * @param string $author
575
	 * @param Member $member
576
	 * @param string $recipient
577
	 * @param string $circleName
578
	 * @param string $password
0 ignored issues
show
Bug introduced by
There is no parameter named $password. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
579
	 */
580
	public function sendMailExitingShares(
581
		array $unknownShares, $author, Member $member, $recipient, $circleName
582
	) {
583
		$data = [];
584
585
		$password = '';
586
		foreach ($unknownShares as $share) {
587
			try {
588
				$item = $this->getMailLinkFromShare($share, $member, $password);
589
				$password = $item['password'];
590
				$data[] = $item;
591
			} catch (TokenDoesNotExistException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
592
			}
593
		}
594
595
		if (sizeof($data) === 0) {
596
			return;
597
		}
598
599
		try {
600
			$template = $this->generateMailExitingShares($author, $circleName);
601
			$this->fillMailExistingShares($template, $data);
602
			$this->sendMailExistingShares($template, $author, $recipient);
603
			$this->sendPasswordExistingShares($author, $recipient, $password);
604
		} catch (Exception $e) {
605
			$this->logger->log(2, 'Failed to send mail about existing share ' . $e->getMessage());
606
		}
607
	}
608
609
610
	/**
611
	 * @param $author
612
	 * @param string $email
613
	 *
614
	 * @param $password
615
	 *
616
	 * @throws Exception
617
	 */
618
	protected function sendPasswordExistingShares($author, $email, $password) {
619
		if (!$this->configService->sendPasswordByMail() || $password === '') {
620
			return;
621
		}
622
623
		$message = $this->mailer->createMessage();
624
625
		$authorUser = $this->userManager->get($author);
626
		$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...
627
		$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...
628
629
		$this->logger->log(0, "Sending password mail about existing files to '" . $email . "'");
630
631
		$plainBodyPart = $this->l10n->t(
632
			"%1\$s shared multiple files with you.\nYou should have already received a separate mail with a link to access them.\n",
633
			[$authorName]
634
		);
635
		$htmlBodyPart = $this->l10n->t(
636
			'%1$s shared multiple files with you. You should have already received a separate mail with a link to access them.',
637
			[$authorName]
638
		);
639
640
		$emailTemplate = $this->mailer->createEMailTemplate(
641
			'sharebymail.RecipientPasswordNotification', [
642
														   'password' => $password,
643
														   'author'   => $author
644
													   ]
645
		);
646
647
		$emailTemplate->setSubject(
648
			$this->l10n->t(
649
				'Password to access files shared to you by %1$s', [$authorName]
650
			)
651
		);
652
		$emailTemplate->addHeader();
653
		$emailTemplate->addHeading($this->l10n->t('Password to access files'), false);
654
		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
655
		$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:'));
656
		$emailTemplate->addBodyText($password);
657
658
		// The "From" contains the sharers name
659
		$instanceName = $this->defaults->getName();
660
		$senderName = $this->l10n->t(
661
			'%1$s via %2$s',
662
			[
663
				$authorName,
664
				$instanceName
665
			]
666
		);
667
668
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
669 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...
670
			$message->setReplyTo([$authorEmail => $authorName]);
671
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
672
		} else {
673
			$emailTemplate->addFooter();
674
		}
675
676
		$message->setTo([$email]);
677
		$message->useTemplate($emailTemplate);
678
		$this->mailer->send($message);
679
	}
680
681
	/**
682
	 * @param array $share
683
	 * @param Member $member
684
	 * @param string $password
685
	 * @param string $token
0 ignored issues
show
Bug introduced by
There is no parameter named $token. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
686
	 *
687
	 * @return array
688
	 * @throws TokenDoesNotExistException
689
	 */
690
	private function getMailLinkFromShare(array $share, Member $member, string $password = '') {
691
		$sharesToken = $this->tokensRequest->generateTokenForMember($member, $share['id'], $password);
692
		$link = $this->urlGenerator->linkToRouteAbsolute(
693
			'files_sharing.sharecontroller.showShare',
694
			['token' => $sharesToken->getToken()]
695
		);
696
		$author = $share['uid_initiator'];
697
698
		$filename = basename($share['file_target']);
699
700
		return [
701
			'author'   => $author,
702
			'link'     => $link,
703
			'password' => $sharesToken->getOrigPassword(),
704
			'filename' => $filename
705
		];
706
	}
707
708
709
	/**
710
	 * @param $author
711
	 * @param string $circleName
712
	 *
713
	 * @return IEMailTemplate
714
	 * @throws Exception
715
	 */
716
	protected function generateMailExitingShares($author, $circleName) {
717
		$this->logger->log(
718
			0, "Generating mail about existing share mail from '" . $author . "' in "
719
			   . $circleName
720
		);
721
722
		$emailTemplate = $this->mailer->createEMailTemplate('circles.ExistingShareNotification', []);
723
		$emailTemplate->addHeader();
724
725
		$text = $this->l10n->t('%s shared multiple files with \'%s\'.', [$author, $circleName]);
726
		$emailTemplate->addBodyText(htmlspecialchars($text), $text);
727
728
		return $emailTemplate;
729
	}
730
731
732
	/**
733
	 * @param IEMailTemplate $emailTemplate
734
	 * @param array $data
735
	 */
736
	protected function fillMailExistingShares(IEMailTemplate $emailTemplate, array $data) {
737
		foreach ($data as $item) {
738
//			$text = $this->l10n->t('%s shared »%s« with you.', [$item['author'], $item['filename']]);
739
//			$emailTemplate->addBodyText(
740
//				htmlspecialchars($text) . '<br>' . htmlspecialchars(
741
//					$this->l10n->t('Click the button below to open it.')
742
//				), $text
743
//			);
744
			$emailTemplate->addBodyButton(
745
				$this->l10n->t('Open »%s«', [htmlspecialchars($item['filename'])]), $item['link']
746
			);
747
		}
748
	}
749
750
751
	/**
752
	 * @param IEMailTemplate $emailTemplate
753
	 * @param $author
754
	 * @param $recipient
755
	 *
756
	 * @throws Exception
757
	 */
758
	protected function sendMailExistingShares(IEMailTemplate $emailTemplate, $author, $recipient) {
759
		$subject = $this->l10n->t('%s shared multiple files with you.', [$author]);
760
//		$emailTemplate->addHeading($subject, false);
761
762
		$instanceName = $this->defaults->getName();
763
		$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]);
764
765
		$message = $this->mailer->createMessage();
766
767
		$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]);
768
		$message->setSubject($subject);
769
		$message->setPlainBody($emailTemplate->renderText());
770
		$message->setHtmlBody($emailTemplate->renderHtml());
771
		$message->setTo([$recipient]);
772
773
		$this->mailer->send($message);
774
	}
775
776
777
	/**
778
	 * @param string $contactId
779
	 *
780
	 * @return array
781
	 */
782 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...
783
		$contact = MiscService::getContactData($contactId);
784
		if (!key_exists('CLOUD', $contact)) {
785
			return [];
786
		}
787
788
		return $contact['CLOUD'];
789
	}
790
791
	/**
792
	 * @param string $contactId
793
	 *
794
	 * @return array
795
	 */
796 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...
797
		$contact = MiscService::getContactData($contactId);
798
		if (!key_exists('EMAIL', $contact)) {
799
			return [];
800
		}
801
802
		return $contact['EMAIL'];
803
	}
804
805
}
806