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

FileSharingBroadcaster::sendMailExistingShares()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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