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

FileSharingBroadcaster::createShareToMember()   C

Complexity

Conditions 15
Paths 56

Size

Total Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 53
rs 5.9166
c 0
b 0
f 0
cc 15
nc 56
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * 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\IBroadcaster;
37
use OCA\Circles\Model\Circle;
38
use OCA\Circles\Model\Member;
39
use OCA\Circles\Model\SharesToken;
40
use OCA\Circles\Model\SharingFrame;
41
use OCA\Circles\Service\ConfigService;
42
use OCA\Circles\Service\MiscService;
43
use OCA\FederatedFileSharing\Notifications;
44
use OCP\AppFramework\QueryException;
45
use OCP\Defaults;
46
use OCP\Federation\ICloudFederationFactory;
47
use OCP\Federation\ICloudFederationProviderManager;
48
use OCP\Federation\ICloudIdManager;
49
use OCP\Files\IRootFolder;
50
use OCP\Files\NotFoundException;
51
use OCP\IL10N;
52
use OCP\ILogger;
53
use OCP\IURLGenerator;
54
use OCP\IUser;
55
use OCP\IUserManager;
56
use OCP\Mail\IEMailTemplate;
57
use OCP\Mail\IMailer;
58
use OCP\Share\Exceptions\IllegalIDChangeException;
59
use OCP\Share\IShare;
60
use OCP\Util;
61
62
63
class FileSharingBroadcaster implements IBroadcaster {
64
65
66
	/** @var bool */
67
	private $initiated = false;
68
69
	/** @var IL10N */
70
	private $l10n = null;
71
72
	/** @var IMailer */
73
	private $mailer;
74
75
	/** @var IRootFolder */
76
	private $rootFolder;
77
78
	/** @var IUserManager */
79
	private $userManager;
80
81
	/** @var ICloudFederationFactory */
82
	private $federationFactory;
83
84
	/** @var ICloudFederationProviderManager */
85
	private $federationProviderManager;
86
87
	/** @var ICloudIdManager */
88
	private $federationCloudIdManager;
89
90
	/** @var Notifications */
91
	private $federationNotifications;
92
93
	/** @var ILogger */
94
	private $logger;
95
96
	/** @var Defaults */
97
	private $defaults;
98
99
	/** @var IURLGenerator */
100
	private $urlGenerator;
101
102
	/** @var SharesRequest */
103
	private $sharesRequest;
104
105
	/** @var TokensRequest */
106
	private $tokensRequest;
107
108
	/** @var ConfigService */
109
	private $configService;
110
111
	/** @var MiscService */
112
	private $miscService;
113
114
	/** @var bool */
115
	private $federatedEnabled = false;
116
117
	/**
118
	 * {@inheritdoc}
119
	 */
120
	public function init() {
121
		if ($this->initiated) {
122
			return;
123
		}
124
125
		$this->initiated = true;
126
		$this->l10n = OC::$server->getL10N(Application::APP_NAME);
127
		$this->mailer = OC::$server->getMailer();
128
		$this->rootFolder = OC::$server->getLazyRootFolder();
129
		$this->userManager = OC::$server->getUserManager();
130
		$this->federationFactory = OC::$server->getCloudFederationFactory();
131
		$this->federationProviderManager = OC::$server->getCloudFederationProviderManager();
132
		$this->federationCloudIdManager = OC::$server->getCloudIdManager();
133
		$this->logger = OC::$server->getLogger();
134
		$this->urlGenerator = OC::$server->getURLGenerator();
135
		try {
136
			$this->defaults = OC::$server->query(Defaults::class);
137
			$this->sharesRequest = OC::$server->query(SharesRequest::class);
138
			$this->tokensRequest = OC::$server->query(TokensRequest::class);
139
			$this->configService = OC::$server->query(ConfigService::class);
140
			$this->miscService = OC::$server->query(MiscService::class);
141
		} 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...
142
			\OC::$server->getLogger()
143
						->log(1, 'Circles: cannot init FileSharingBroadcaster - ' . $e->getMessage());
144
		}
145
146
		try {
147
			$this->federationNotifications =
148
				OC::$server->query(\OCA\FederatedFileSharing\Notifications::class);
149
			$this->federatedEnabled = true;
150
		} 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...
151
		}
152
153
	}
154
155
156
	/**
157
	 * {@inheritdoc}
158
	 */
159
	public function end() {
160
	}
161
162
163
	/**
164
	 * {@inheritdoc}
165
	 */
166
	public function createShareToCircle(SharingFrame $frame, Circle $circle) {
167
		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...
168
			return false;
169
		}
170
171
		return true;
172
	}
173
174
175
	/**
176
	 * {@inheritdoc}
177
	 */
178
	public function deleteShareToCircle(SharingFrame $frame, Circle $circle) {
179
		return true;
180
	}
181
182
183
	/**
184
	 * {@inheritdoc}
185
	 */
186
	public function editShareToCircle(SharingFrame $frame, Circle $circle) {
187
		return true;
188
	}
189
190
191
	/**
192
	 * {@inheritdoc}
193
	 * @throws IllegalIDChangeException
194
	 */
195
	public function createShareToMember(SharingFrame $frame, Member $member) {
196
		if (!$frame->is0Circle()) {
197
			return false;
198
		}
199
200
		$payload = $frame->getPayload();
201
		if (!key_exists('share', $payload)) {
202
			return false;
203
		}
204
205
		$share = $this->generateShare($payload['share']);
206
		if ($member->getType() === Member::TYPE_MAIL || $member->getType() === Member::TYPE_CONTACT) {
207
			try {
208
				$circle = $frame->getCircle();
209
210
				// federated shared in contact
211
				$clouds = $this->getCloudsFromContact($member->getUserId());
212
				if ($this->federatedEnabled && !empty($clouds)) {
213
					$sent = false;
214
					foreach ($clouds as $cloudId) {
215
						$token = $this->tokensRequest->generateTokenForMember($member, $share->getId());
216
						if ($this->sharedByFederated($circle, $share, $cloudId, $token)) {
217
							$sent = true;
218
						}
219
					}
220
221
					if ($sent) {
222
						return true;
223
					}
224
				}
225
226
				$password = '';
227
				if ($this->configService->enforcePasswordProtection()) {
228
					$password = $this->miscService->token(15);
229
				}
230
231
				$token = $this->tokensRequest->generateTokenForMember($member, $share->getId(), $password);
232
				if ($token !== '') {
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, $token, $password);
240
					}
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
		$this->init();
272
		if ($member->getType() !== Member::TYPE_MAIL && $member->getType() !== Member::TYPE_CONTACT) {
273
			return;
274
		}
275
276
		//
277
		// TODO: check that contact got cloudIds. if so, broadcast share to federated cloud Id;
278
		//
279
280
		$allShares = $this->sharesRequest->getSharesForCircle($member->getCircleId());
281
		$knownShares = array_map(
282
			function(SharesToken $shareToken) {
283
				return $shareToken->getShareId();
284
			},
285
			$this->tokensRequest->getTokensFromMember($member)
286
		);
287
288
		$unknownShares = [];
289
		foreach ($allShares as $share) {
290
			if (!in_array($share['id'], $knownShares)) {
291
				$unknownShares[] = $share;
292
			}
293
		}
294
295
		$author = $circle->getViewer()
296
						 ->getUserId();
297
		$this->sendMailExitingShares(
298
			$unknownShares, MiscService::getDisplay($author, Member::TYPE_USER), $member, $circle->getName()
299
		);
300
	}
301
302
303
	/**
304
	 * recreate the share from the JSON payload.
305
	 *
306
	 * @param array $data
307
	 *
308
	 * @return IShare
0 ignored issues
show
Documentation introduced by
Should the return type not be Share?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
309
	 * @throws IllegalIDChangeException
310
	 */
311
	private function generateShare($data) {
312
		$this->logger->log(0, 'Regenerate shares from payload: ' . json_encode($data));
313
314
		$share = new Share($this->rootFolder, $this->userManager);
315
		$share->setId($data['id']);
316
		$share->setSharedBy($data['sharedBy']);
317
		$share->setSharedWith($data['sharedWith']);
318
		$share->setNodeId($data['nodeId']);
319
		$share->setShareOwner($data['shareOwner']);
320
		$share->setPermissions($data['permissions']);
321
		$share->setToken($data['token']);
322
		$share->setPassword($data['password']);
323
324
		return $share;
325
	}
326
327
328
	/**
329
	 * @param Circle $circle
330
	 * @param IShare $share
331
	 * @param string $address
332
	 * @param string $token
333
	 *
334
	 * @return bool
335
	 */
336
	private function sharedByFederated(Circle $circle, IShare $share, string $address, string $token): bool {
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...
337
338
		try {
339
			$cloudId = $this->federationCloudIdManager->resolveCloudId($address);
340
341
			$localUrl = $this->urlGenerator->getAbsoluteURL('/');
342
			$sharedByFederatedId = $share->getSharedBy();
343
			if ($this->userManager->userExists($sharedByFederatedId)) {
344
				$cloudId = $this->federationCloudIdManager->getCloudId($sharedByFederatedId, $localUrl);
345
				$sharedByFederatedId = $cloudId->getId();
346
			}
347
			$ownerCloudId = $this->federationCloudIdManager->getCloudId($share->getShareOwner(), $localUrl);
348
349
			$send = $this->federationNotifications->sendRemoteShare(
350
				$token,
351
				$address,
352
				$share->getNode()
353
					  ->getName(),
354
				$share->getId(),
355
				$share->getShareOwner(),
356
				$ownerCloudId->getId(),
357
				$share->getSharedBy(),
358
				$sharedByFederatedId,
359
				Share::TYPE_USER
360
			);
361
362
			return $send;
363
		} catch (\Exception $e) {
364
			$this->logger->logException(
365
				$e, [
366
					  'message' => 'Failed to notify remote server of circles-federated share',
367
					  'level'   => ILogger::ERROR,
368
					  'app'     => 'circles',
369
				  ]
370
			);
371
		}
372
373
		return false;
374
	}
375
376
377
	/**
378
	 * @param Circle $circle
379
	 * @param IShare $share
380
	 * @param string $email
381
	 * @param string $token
382
	 * @param string $password
383
	 */
384
	private function sharedByMail(Circle $circle, IShare $share, $email, $token, $password) {
385
		// genelink
386
		$link = $this->urlGenerator->linkToRouteAbsolute(
387
			'files_sharing.sharecontroller.showShare',
388
			['token' => $token]
389
		);
390
391
		try {
392
			$this->sendMail(
393
				$share->getNode()
394
					  ->getName(), $link,
395
				MiscService::getDisplay($share->getSharedBy(), Member::TYPE_USER),
396
				$circle->getName(), $email
397
			);
398
			$this->sendPasswordByMail(
399
				$share, MiscService::getDisplay($share->getSharedBy(), Member::TYPE_USER),
400
				$email, $password
401
			);
402
		} catch (Exception $e) {
403
			OC::$server->getLogger()
404
					   ->log(1, 'Circles::sharedByMail - mail were not sent: ' . $e->getMessage());
405
		}
406
	}
407
408
409
	/**
410
	 * @param $fileName
411
	 * @param string $link
412
	 * @param string $author
413
	 * @param $circleName
414
	 * @param string $email
415
	 *
416
	 * @throws Exception
417
	 */
418
	protected function sendMail($fileName, $link, $author, $circleName, $email) {
419
		$message = $this->mailer->createMessage();
420
421
		$this->logger->log(
422
			0, "Sending mail to circle '" . $circleName . "': " . $email . ' file: ' . $fileName
423
			   . ' - link: ' . $link
424
		);
425
426
		$subject = $this->l10n->t('%s shared »%s« with you.', [$author, $fileName]);
427
		$text = $this->l10n->t('%s shared »%s« with \'%s\'.', [$author, $fileName, $circleName]);
428
429
		$emailTemplate =
430
			$this->generateEmailTemplate($subject, $text, $fileName, $link, $author, $circleName);
431
432
		$instanceName = $this->defaults->getName();
433
		$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]);
434
435
		$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]);
436
		$message->setSubject($subject);
437
		$message->setPlainBody($emailTemplate->renderText());
438
		$message->setHtmlBody($emailTemplate->renderHtml());
439
		$message->setTo([$email]);
440
441
		$this->mailer->send($message);
442
	}
443
444
445
	/**
446
	 * @param IShare $share
447
	 * @param string $circleName
448
	 * @param string $email
449
	 *
450
	 * @param $password
451
	 *
452
	 * @throws NotFoundException
453
	 * @throws Exception
454
	 */
455
	protected function sendPasswordByMail(IShare $share, $circleName, $email, $password) {
456
		if (!$this->configService->sendPasswordByMail() || $password === '') {
457
			return;
458
		}
459
460
		$message = $this->mailer->createMessage();
461
462
		$this->logger->log(0, "Sending password mail to circle '" . $circleName . "': " . $email);
463
464
		$filename = $share->getNode()
465
						  ->getName();
466
		$initiator = $share->getSharedBy();
467
		$shareWith = $share->getSharedWith();
468
469
		$initiatorUser = $this->userManager->get($initiator);
470
		$initiatorDisplayName =
471
			($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...
472
		$initiatorEmailAddress =
473
			($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...
474
475
		$plainBodyPart = $this->l10n->t(
476
			"%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n",
477
			[$initiatorDisplayName, $filename]
478
		);
479
		$htmlBodyPart = $this->l10n->t(
480
			'%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.',
481
			[$initiatorDisplayName, $filename]
482
		);
483
484
		$emailTemplate = $this->mailer->createEMailTemplate(
485
			'sharebymail.RecipientPasswordNotification', [
486
														   'filename'       => $filename,
487
														   'password'       => $password,
488
														   'initiator'      => $initiatorDisplayName,
489
														   'initiatorEmail' => $initiatorEmailAddress,
490
														   'shareWith'      => $shareWith,
491
													   ]
492
		);
493
494
		$emailTemplate->setSubject(
495
			$this->l10n->t(
496
				'Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName]
497
			)
498
		);
499
		$emailTemplate->addHeader();
500
		$emailTemplate->addHeading($this->l10n->t('Password to access »%s«', [$filename]), false);
501
		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
502
		$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:'));
503
		$emailTemplate->addBodyText($password);
504
505
		// The "From" contains the sharers name
506
		$instanceName = $this->defaults->getName();
507
		$senderName = $this->l10n->t(
508
			'%1$s via %2$s',
509
			[
510
				$initiatorDisplayName,
511
				$instanceName
512
			]
513
		);
514
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
515 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...
516
			$message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]);
517
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
518
		} else {
519
			$emailTemplate->addFooter();
520
		}
521
522
		$message->setTo([$email]);
523
		$message->useTemplate($emailTemplate);
524
		$this->mailer->send($message);
525
	}
526
527
528
	/**
529
	 * @param $subject
530
	 * @param $text
531
	 * @param $fileName
532
	 * @param $link
533
	 * @param string $author
534
	 * @param string $circleName
535
	 *
536
	 * @return IEMailTemplate
537
	 */
538
	private function generateEmailTemplate($subject, $text, $fileName, $link, $author, $circleName
539
	) {
540
		$emailTemplate = $this->mailer->createEMailTemplate(
541
			'circles.ShareNotification', [
542
										   'fileName'   => $fileName,
543
										   'fileLink'   => $link,
544
										   'author'     => $author,
545
										   'circleName' => $circleName,
546
									   ]
547
		);
548
549
		$emailTemplate->addHeader();
550
		$emailTemplate->addHeading($subject, false);
551
		$emailTemplate->addBodyText(
552
			htmlspecialchars($text) . '<br>' . htmlspecialchars(
553
				$this->l10n->t('Click the button below to open it.')
554
			), $text
555
		);
556
		$emailTemplate->addBodyButton(
557
			$this->l10n->t('Open »%s«', [htmlspecialchars($fileName)]), $link
558
		);
559
560
		return $emailTemplate;
561
	}
562
563
564
	/**
565
	 * @param array $unknownShares
566
	 * @param string $author
567
	 * @param Member $member
568
	 * @param string $circleName
569
	 */
570
	private function sendMailExitingShares(array $unknownShares, $author, Member $member, $circleName) {
571
		$password = '';
572
		if ($this->configService->enforcePasswordProtection()) {
573
			try {
574
				$password = $this->miscService->token(15);
575
			} catch (Exception $e) {
576
				return;
577
			}
578
		}
579
580
		$data = [];
581
		foreach ($unknownShares as $share) {
582
			$data[] = $this->getMailLinkFromShare($share, $member, $password);
583
		}
584
585
586
		if (sizeof($data) === 0) {
587
			return;
588
		}
589
590
		try {
591
			$template = $this->generateMailExitingShares($author, $circleName);
592
			$this->fillMailExistingShares($template, $data);
593
			$this->sendMailExistingShares($template, $author, $member->getUserId());
594
			$this->sendPasswordExistingShares($author, $member->getUserId(), $password);
595
		} catch (Exception $e) {
596
			$this->logger->log(2, 'Failed to send mail about existing share ' . $e->getMessage());
597
		}
598
	}
599
600
601
	/**
602
	 * @param $author
603
	 * @param string $email
604
	 *
605
	 * @param $password
606
	 *
607
	 * @throws Exception
608
	 */
609
	protected function sendPasswordExistingShares($author, $email, $password) {
610
		if (!$this->configService->sendPasswordByMail() || $password === '') {
611
			return;
612
		}
613
614
		$message = $this->mailer->createMessage();
615
616
		$authorUser = $this->userManager->get($author);
617
		$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...
618
		$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...
619
620
		$this->logger->log(0, "Sending password mail about existing files to '" . $email . "'");
621
622
		$plainBodyPart = $this->l10n->t(
623
			"%1\$s shared multiple files with you.\nYou should have already received a separate mail with a link to access them.\n",
624
			[$authorName]
625
		);
626
		$htmlBodyPart = $this->l10n->t(
627
			'%1$s shared multiple files with you. You should have already received a separate mail with a link to access them.',
628
			[$authorName]
629
		);
630
631
		$emailTemplate = $this->mailer->createEMailTemplate(
632
			'sharebymail.RecipientPasswordNotification', [
633
														   'password' => $password,
634
														   'author'   => $author
635
													   ]
636
		);
637
638
		$emailTemplate->setSubject(
639
			$this->l10n->t(
640
				'Password to access files shared to you by %1$s', [$authorName]
641
			)
642
		);
643
		$emailTemplate->addHeader();
644
		$emailTemplate->addHeading($this->l10n->t('Password to access files'), false);
645
		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
646
		$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:'));
647
		$emailTemplate->addBodyText($password);
648
649
		// The "From" contains the sharers name
650
		$instanceName = $this->defaults->getName();
651
		$senderName = $this->l10n->t(
652
			'%1$s via %2$s',
653
			[
654
				$authorName,
655
				$instanceName
656
			]
657
		);
658
659
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
660 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...
661
			$message->setReplyTo([$authorEmail => $authorName]);
662
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
663
		} else {
664
			$emailTemplate->addFooter();
665
		}
666
667
		$message->setTo([$email]);
668
		$message->useTemplate($emailTemplate);
669
		$this->mailer->send($message);
670
	}
671
672
	/**
673
	 * @param array $share
674
	 * @param Member $member
675
	 * @param string $password
676
	 *
677
	 * @return array
678
	 */
679
	private function getMailLinkFromShare(array $share, Member $member, $password) {
680
		$token = $this->tokensRequest->generateTokenForMember($member, $share['id'], $password);
681
		$link = $this->urlGenerator->linkToRouteAbsolute(
682
			'files_sharing.sharecontroller.showShare',
683
			['token' => $token]
684
		);
685
		$author = $share['uid_initiator'];
686
687
		$filename = basename($share['file_target']);
688
689
		return [
690
			'author'   => $author,
691
			'link'     => $link,
692
			'password' => $password,
693
			'filename' => $filename
694
		];
695
	}
696
697
698
	/**
699
	 * @param $author
700
	 * @param string $circleName
701
	 *
702
	 * @return IEMailTemplate
703
	 * @throws Exception
704
	 */
705
	protected function generateMailExitingShares($author, $circleName) {
706
		$this->logger->log(
707
			0, "Generating mail about existing share mail from '" . $author . "' in "
708
			   . $circleName
709
		);
710
711
		$emailTemplate = $this->mailer->createEMailTemplate('circles.ExistingShareNotification', []);
712
		$emailTemplate->addHeader();
713
714
		$text = $this->l10n->t('%s shared multiple files with \'%s\'.', [$author, $circleName]);
715
		$emailTemplate->addBodyText(htmlspecialchars($text), $text);
716
717
		return $emailTemplate;
718
	}
719
720
721
	/**
722
	 * @param IEMailTemplate $emailTemplate
723
	 * @param array $data
724
	 */
725
	protected function fillMailExistingShares(IEMailTemplate $emailTemplate, array $data) {
726
		foreach ($data as $item) {
727
//			$text = $this->l10n->t('%s shared »%s« with you.', [$item['author'], $item['filename']]);
728
//			$emailTemplate->addBodyText(
729
//				htmlspecialchars($text) . '<br>' . htmlspecialchars(
730
//					$this->l10n->t('Click the button below to open it.')
731
//				), $text
732
//			);
733
			$emailTemplate->addBodyButton(
734
				$this->l10n->t('Open »%s«', [htmlspecialchars($item['filename'])]), $item['link']
735
			);
736
		}
737
	}
738
739
740
	/**
741
	 * @param IEMailTemplate $emailTemplate
742
	 * @param $author
743
	 * @param $recipient
744
	 *
745
	 * @throws Exception
746
	 */
747
	protected function sendMailExistingShares(IEMailTemplate $emailTemplate, $author, $recipient) {
748
		$subject = $this->l10n->t('%s shared multiple files with you.', [$author]);
749
//		$emailTemplate->addHeading($subject, false);
750
751
		$instanceName = $this->defaults->getName();
752
		$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]);
753
754
		$message = $this->mailer->createMessage();
755
756
		$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]);
757
		$message->setSubject($subject);
758
		$message->setPlainBody($emailTemplate->renderText());
759
		$message->setHtmlBody($emailTemplate->renderHtml());
760
		$message->setTo([$recipient]);
761
762
		$this->mailer->send($message);
763
	}
764
765
766
	/**
767
	 * @param string $contactId
768
	 *
769
	 * @return array
770
	 */
771 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...
772
		$contact = MiscService::getContactData($contactId);
773
		if (!key_exists('CLOUD', $contact)) {
774
			return [];
775
		}
776
777
		return $contact['CLOUD'];
778
	}
779
780
	/**
781
	 * @param string $contactId
782
	 *
783
	 * @return array
784
	 */
785 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...
786
		$contact = MiscService::getContactData($contactId);
787
		if (!key_exists('EMAIL', $contact)) {
788
			return [];
789
		}
790
791
		return $contact['EMAIL'];
792
	}
793
794
}
795