Completed
Pull Request — master (#609)
by Maxence
02:38
created

SingleMemberAdd::confirmPatron()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 3
nc 3
nop 2
1
<?php
2
3
declare(strict_types=1);
4
5
6
/**
7
 * Circles - Bring cloud-users closer together.
8
 *
9
 * This file is licensed under the Affero General Public License version 3 or
10
 * later. See the COPYING file.
11
 *
12
 * @author Maxence Lange <[email protected]>
13
 * @copyright 2021
14
 * @license GNU AGPL version 3 or any later version
15
 *
16
 * This program is free software: you can redistribute it and/or modify
17
 * it under the terms of the GNU Affero General Public License as
18
 * published by the Free Software Foundation, either version 3 of the
19
 * License, or (at your option) any later version.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 *
29
 */
30
31
32
namespace OCA\Circles\FederatedItems;
33
34
35
use daita\MySmallPhpTools\Exceptions\InvalidItemException;
36
use daita\MySmallPhpTools\Exceptions\RequestNetworkException;
37
use daita\MySmallPhpTools\Exceptions\SignatoryException;
38
use daita\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Logger;
39
use daita\MySmallPhpTools\Traits\TStringTools;
40
use Exception;
41
use OC\User\NoUserException;
42
use OCA\Circles\Db\MemberRequest;
43
use OCA\Circles\Exceptions\CircleNotFoundException;
44
use OCA\Circles\Exceptions\FederatedItemBadRequestException;
45
use OCA\Circles\Exceptions\FederatedItemException;
46
use OCA\Circles\Exceptions\FederatedItemNotFoundException;
47
use OCA\Circles\Exceptions\FederatedItemRemoteException;
48
use OCA\Circles\Exceptions\FederatedItemServerException;
49
use OCA\Circles\Exceptions\FederatedUserException;
50
use OCA\Circles\Exceptions\FederatedUserNotFoundException;
51
use OCA\Circles\Exceptions\InvalidIdException;
52
use OCA\Circles\Exceptions\MemberNotFoundException;
53
use OCA\Circles\Exceptions\MembersLimitException;
54
use OCA\Circles\Exceptions\OwnerNotFoundException;
55
use OCA\Circles\Exceptions\RemoteInstanceException;
56
use OCA\Circles\Exceptions\RemoteNotFoundException;
57
use OCA\Circles\Exceptions\RemoteResourceNotFoundException;
58
use OCA\Circles\Exceptions\RequestBuilderException;
59
use OCA\Circles\Exceptions\SingleCircleNotFoundException;
60
use OCA\Circles\Exceptions\TokenDoesNotExistException;
61
use OCA\Circles\Exceptions\UnknownRemoteException;
62
use OCA\Circles\Exceptions\UserTypeNotFoundException;
63
use OCA\Circles\IFederatedItem;
64
use OCA\Circles\IFederatedItemAsyncProcess;
65
use OCA\Circles\IFederatedItemHighSeverity;
66
use OCA\Circles\IFederatedItemMemberCheckNotRequired;
67
use OCA\Circles\IFederatedItemMemberRequired;
68
use OCA\Circles\IFederatedUser;
69
use OCA\Circles\Model\Circle;
70
use OCA\Circles\Model\DeprecatedCircle;
71
use OCA\Circles\Model\DeprecatedMember;
72
use OCA\Circles\Model\Federated\FederatedEvent;
73
use OCA\Circles\Model\Federated\RemoteInstance;
74
use OCA\Circles\Model\FederatedUser;
75
use OCA\Circles\Model\Helpers\MemberHelper;
76
use OCA\Circles\Model\ManagedModel;
77
use OCA\Circles\Model\Member;
78
use OCA\Circles\Model\SharesToken;
79
use OCA\Circles\Service\CircleService;
80
use OCA\Circles\Service\ConfigService;
81
use OCA\Circles\Service\EventService;
82
use OCA\Circles\Service\FederatedUserService;
83
use OCA\Circles\Service\MembershipService;
84
use OCA\Circles\Service\RemoteStreamService;
85
use OCA\Circles\StatusCode;
86
use OCP\IUser;
87
use OCP\IUserManager;
88
use OCP\Mail\IEMailTemplate;
89
use OCP\Util;
90
91
92
/**
93
 * Class MemberAdd
94
 *
95
 * @package OCA\Circles\GlobalScale
96
 */
97
class SingleMemberAdd implements
98
	IFederatedItem,
99
	IFederatedItemAsyncProcess,
100
	IFederatedItemHighSeverity,
101
	IFederatedItemMemberRequired,
102
	IFederatedItemMemberCheckNotRequired {
103
104
105
	use TStringTools;
106
	use TNC22Logger;
107
108
109
	/** @var IUserManager */
110
	protected $userManager;
111
112
	/** @var MemberRequest */
113
	protected $memberRequest;
114
115
	/** @var FederatedUserService */
116
	protected $federatedUserService;
117
118
	/** @var RemoteStreamService */
119
	protected $remoteStreamService;
120
121
	/** @var CircleService */
122
	protected $circleService;
123
124
	/** @var MembershipService */
125
	protected $membershipService;
126
127
	/** @var EventService */
128
	protected $eventService;
129
130
	/** @var ConfigService */
131
	protected $configService;
132
133
134
	/**
135
	 * SingleMemberAdd constructor.
136
	 *
137
	 * @param IUserManager $userManager
138
	 * @param MemberRequest $memberRequest
139
	 * @param FederatedUserService $federatedUserService
140
	 * @param RemoteStreamService $remoteStreamService
141
	 * @param CircleService $circleService
142
	 * @param MembershipService $membershipService
143
	 * @param EventService $eventService
144
	 * @param ConfigService $configService
145
	 */
146 View Code Duplication
	public function __construct(
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...
147
		IUserManager $userManager, MemberRequest $memberRequest, FederatedUserService $federatedUserService,
148
		RemoteStreamService $remoteStreamService, CircleService $circleService,
149
		MembershipService $membershipService, EventService $eventService, ConfigService $configService
150
	) {
151
		$this->userManager = $userManager;
152
		$this->memberRequest = $memberRequest;
153
		$this->federatedUserService = $federatedUserService;
154
		$this->remoteStreamService = $remoteStreamService;
155
		$this->circleService = $circleService;
156
		$this->membershipService = $membershipService;
157
		$this->eventService = $eventService;
158
		$this->configService = $configService;
159
	}
160
161
162
	/**
163
	 * @param FederatedEvent $event
164
	 *
165
	 * @throws FederatedItemBadRequestException
166
	 * @throws FederatedItemNotFoundException
167
	 * @throws FederatedItemServerException
168
	 * @throws FederatedItemRemoteException
169
	 * @throws FederatedItemException
170
	 * @throws RequestBuilderException
171
	 */
172
	public function verify(FederatedEvent $event): void {
173
		$member = $event->getMember();
174
		$circle = $event->getCircle();
175
		$initiator = $circle->getInitiator();
176
177
		$initiatorHelper = new MemberHelper($initiator);
178
		$initiatorHelper->mustBeModerator();
179
180
		$member = $this->generateMember($event, $circle, $member);
181
182
		$event->setMembers([$member]);
183
		$event->setOutcome($member->jsonSerialize());
184
185
		return;
186
187
188
//		$member = $this->membersRequest->getFreshNewMember(
189
//			$circle->getUniqueId(), $ident, $eventMember->getType(), $eventMember->getInstance()
190
//		);
191
//		$member->hasToBeInviteAble()
192
//
193
//		$this->membersService->addMemberBasedOnItsType($circle, $member);
194
//
195
//		$password = '';
196
//		$sendPasswordByMail = false;
197
//		if ($this->configService->enforcePasswordProtection($circle)) {
198
//			if ($circle->getSetting('password_single_enabled') === 'true') {
199
//				$password = $circle->getPasswordSingle();
200
//			} else {
201
//				$sendPasswordByMail = true;
202
//				$password = $this->miscService->token(15);
203
//			}
204
//		}
205
//
206
//		$event->setData(
207
//			new SimpleDataStore(
208
//				[
209
//					'password'       => $password,
210
//					'passwordByMail' => $sendPasswordByMail
211
//				]
212
//			)
213
//		);
214
	}
215
216
217
	/**
218
	 * @param FederatedEvent $event
219
	 *
220
	 * @throws InvalidIdException
221
	 * @throws RequestBuilderException
222
	 */
223
	public function manage(FederatedEvent $event): void {
224
		$member = $event->getMember();
225
226
		if (!$this->insertOrUpdate($member)) {
227
			return;
228
		}
229
230
		$this->membershipService->onUpdate($member->getSingleId());
231
232
		$this->eventService->singleMemberAdding($event);
233
234
//
235
//		//
236
//		// TODO: verifiez comment se passe le cached name sur un member_add
237
//		//
238
//		$cachedName = $member->getCachedName();
239
//		$password = $event->getData()
240
//						  ->g('password');
241
//
242
//		$shares = $this->generateUnknownSharesLinks($circle, $member, $password);
243
//		$result = [
244
//			'unknownShares' => $shares,
245
//			'cachedName'    => $cachedName
246
//		];
247
//
248
//		if ($member->getType() === DeprecatedMember::TYPE_CONTACT
249
//			&& $this->configService->isLocalInstance($member->getInstance())) {
250
//			$result['contact'] = $this->miscService->getInfosFromContact($member);
251
//		}
252
//
253
//		$event->setResult(new SimpleDataStore($result));
254
//		$this->eventsService->onMemberNew($circle, $member);
255
	}
256
257
258
	/**
259
	 * @param FederatedEvent $event
260
	 * @param array $results
261
	 */
262
	public function result(FederatedEvent $event, array $results): void {
263
		$this->eventService->singleMemberAdded($event, $results);
264
265
//		$password = $cachedName = '';
266
//		$circle = $member = null;
267
//		$links = [];
268
//		$recipients = [];
269
//		foreach ($events as $event) {
270
//			$data = $event->getData();
271
//			if ($data->gBool('passwordByMail') !== false) {
272
//				$password = $data->g('password');
273
//			}
274
//			$circle = $event->getDeprecatedCircle();
275
//			$member = $event->getMember();
276
//			$result = $event->getResult();
277
//			if ($result->g('cachedName') !== '') {
278
//				$cachedName = $result->g('cachedName');
279
//			}
280
//
281
//			$links = array_merge($links, $result->gArray('unknownShares'));
282
//			$contact = $result->gArray('contact');
283
//			if (!empty($contact)) {
284
//				$recipients = $contact['emails'];
285
//			}
286
//		}
287
//
288
//		if (empty($links) || $circle === null || $member === null) {
289
//			return;
290
//		}
291
//
292
//		if ($cachedName !== '') {
293
//			$member->setCachedName($cachedName);
294
//			$this->membersService->updateMember($member);
295
//		}
296
//
297
//		if ($member->getType() === DeprecatedMember::TYPE_MAIL
298
//			|| $member->getType() === DeprecatedMember::TYPE_CONTACT) {
299
//			if ($member->getType() === DeprecatedMember::TYPE_MAIL) {
300
//				$recipients = [$member->getUserId()];
301
//			}
302
//
303
//			foreach ($recipients as $recipient) {
304
//				$this->memberIsMailbox($circle, $recipient, $links, $password);
305
//			}
306
//		}
307
	}
308
309
310
	/**
311
	 * @param Circle $circle
312
	 * @param Member $member
313
	 *
314
	 * @return Member
315
	 * @throws CircleNotFoundException
316
	 * @throws FederatedItemBadRequestException
317
	 * @throws FederatedItemException
318
	 * @throws FederatedUserException
319
	 * @throws FederatedUserNotFoundException
320
	 * @throws InvalidIdException
321
	 * @throws MembersLimitException
322
	 * @throws OwnerNotFoundException
323
	 * @throws RemoteInstanceException
324
	 * @throws RemoteNotFoundException
325
	 * @throws RemoteResourceNotFoundException
326
	 * @throws SingleCircleNotFoundException
327
	 * @throws UnknownRemoteException
328
	 * @throws UserTypeNotFoundException
329
	 * @throws RequestBuilderException
330
	 */
331
	protected function generateMember(FederatedEvent $event, Circle $circle, Member $member): Member {
332
		try {
333
			if ($member->getSingleId() !== '') {
334
				$userId = $member->getSingleId() . '@' . $member->getInstance();
335
				$federatedUser = $this->federatedUserService->getFederatedUser($userId, Member::TYPE_SINGLE);
336
			} else {
337
				$userId = $member->getUserId() . '@' . $member->getInstance();
338
				$federatedUser =
339
					$this->federatedUserService->getFederatedUser($userId, $member->getUserType());
340
			}
341
		} catch (MemberNotFoundException $e) {
342
			throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[120], 120);
0 ignored issues
show
Bug introduced by
The property MEMBER_ADD cannot be accessed from this context as it is declared private in class OCA\Circles\StatusCode.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
343
		}
344
345
		if ($federatedUser->getBasedOn()->isConfig(Circle::CFG_ROOT)) {
346
			throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[125], 125);
0 ignored issues
show
Bug introduced by
The property MEMBER_ADD cannot be accessed from this context as it is declared private in class OCA\Circles\StatusCode.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
347
		}
348
349
		if ($member->getSingleId() === $circle->getSingleId()) {
350
			throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[128], 128);
0 ignored issues
show
Bug introduced by
The property MEMBER_ADD cannot be accessed from this context as it is declared private in class OCA\Circles\StatusCode.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
351
		}
352
353
		if (!$this->configService->isLocalInstance($member->getInstance())) {
354
			if ($circle->isConfig(Circle::CFG_LOCAL)) {
355
				throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[126], 126);
0 ignored issues
show
Bug introduced by
The property MEMBER_ADD cannot be accessed from this context as it is declared private in class OCA\Circles\StatusCode.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
356
			}
357
358
			if (!$circle->isConfig(Circle::CFG_FEDERATED)) {
359
				$remoteInstance = $this->remoteStreamService->getCachedRemoteInstance($member->getInstance());
360
				if ($remoteInstance->getType() !== RemoteInstance::TYPE_GLOBALSCALE) {
361
					throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[127], 127);
0 ignored issues
show
Bug introduced by
The property MEMBER_ADD cannot be accessed from this context as it is declared private in class OCA\Circles\StatusCode.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
362
				}
363
			}
364
		}
365
366
		$member->importFromIFederatedUser($federatedUser);
367
		$member->setCircleId($circle->getSingleId());
368
		$member->setCircle($circle);
369
370
		$this->confirmPatron($event, $member);
371
		$member->setNoteObj('invitedBy', $member->getInvitedBy());
372
373
		$this->manageMemberStatus($circle, $member);
374
375
		$this->circleService->confirmCircleNotFull($circle);
376
377
		// The idea is that adding the member during the self::verify() will help during the broadcasting
378
		// of the event to Federated RemoteInstance for their first member.
379
		$this->insertOrUpdate($member);
380
381
		//	$member->setDisplayName($member->getBasedOn()->getDisplayName());
382
383
		// TODO: Managing cached name
384
		//		$member->setCachedName($eventMember->getCachedName());
385
		return $member;
386
	}
387
388
389
	/**
390
	 * @param Circle $circle
391
	 * @param Member $member
392
	 *
393
	 * @throws FederatedItemBadRequestException
394
	 * @throws RequestBuilderException
395
	 */
396
	private function manageMemberStatus(Circle $circle, Member $member) {
397
		try {
398
			$knownMember = $this->memberRequest->searchMember($member);
399
			$member->setId($knownMember->getId());
400
401
			if ($knownMember->getLevel() === Member::LEVEL_NONE) {
402
				switch ($knownMember->getStatus()) {
403
					case Member::STATUS_BLOCKED:
404
						if ($circle->isConfig(Circle::CFG_INVITE)) {
405
							$member->setStatus(Member::STATUS_INVITED);
406
						}
407
408
						return;
409
410
					case Member::STATUS_REQUEST:
411
						$member->setLevel(Member::LEVEL_MEMBER);
412
						$member->setStatus(Member::STATUS_MEMBER);
413
414
						return;
415
416
					case Member::STATUS_INVITED:
417
						throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[123], 123);
0 ignored issues
show
Bug introduced by
The property MEMBER_ADD cannot be accessed from this context as it is declared private in class OCA\Circles\StatusCode.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
418
				}
419
			}
420
421
			throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[122], 122);
0 ignored issues
show
Bug introduced by
The property MEMBER_ADD cannot be accessed from this context as it is declared private in class OCA\Circles\StatusCode.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
422
		} catch (MemberNotFoundException $e) {
423
424
			$member->setId($this->uuid(ManagedModel::ID_LENGTH));
425
426 View Code Duplication
			if ($circle->isConfig(Circle::CFG_INVITE)) {
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...
427
				$member->setStatus(Member::STATUS_INVITED);
428
			} else {
429
				$member->setLevel(Member::LEVEL_MEMBER);
430
				$member->setStatus(Member::STATUS_MEMBER);
431
			}
432
		}
433
	}
434
435
436
	/**
437
	 * @param FederatedEvent $event
438
	 * @param Member $member
439
	 *
440
	 * @throws FederatedItemBadRequestException
441
	 * @throws FederatedUserException
442
	 * @throws RequestBuilderException
443
	 */
444
	private function confirmPatron(FederatedEvent $event, Member $member): void {
445
		if (!$member->hasInvitedBy()) {
446
			throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[129], 129);
0 ignored issues
show
Bug introduced by
The property MEMBER_ADD cannot be accessed from this context as it is declared private in class OCA\Circles\StatusCode.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
447
		}
448
449
		$patron = $member->getInvitedBy();
450
		\OC::$server->getLogger()->log(3, '### ' . $event->getOrigin() . ' - ' . $patron->getInstance());
451
		if ($patron->getInstance() !== $event->getOrigin()) {
452
			throw new FederatedItemBadRequestException(StatusCode::$MEMBER_ADD[130], 130);
0 ignored issues
show
Bug introduced by
The property MEMBER_ADD cannot be accessed from this context as it is declared private in class OCA\Circles\StatusCode.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
453
		}
454
455
		$this->federatedUserService->confirmLocalSingleId($patron);
456
	}
457
458
459
	/**
460
	 * @param Member $member
461
	 *
462
	 * @return bool
463
	 * @throws InvalidIdException
464
	 */
465
	private function insertOrUpdate(Member $member): bool {
466
		try {
467
			$federatedUser = new FederatedUser();
468
			$federatedUser->importFromIFederatedUser($member);
469
			$this->federatedUserService->confirmLocalSingleId($federatedUser);
470
		} catch (FederatedUserException $e) {
471
			$this->e($e, ['member' => $member]);
472
473
			return false;
474
		}
475
476
		$this->memberRequest->insertOrUpdate($member);
477
478
		return true;
479
	}
480
481
482
	/**
483
	 * confirm the validity of a UserId, based on UserType.
484
	 *
485
	 * @param IFederatedUser $member
486
	 *
487
	 * @throws FederatedUserException
488
	 * @throws InvalidIdException
489
	 * @throws UserTypeNotFoundException
490
	 * @throws CircleNotFoundException
491
	 * @throws FederatedUserNotFoundException
492
	 * @throws OwnerNotFoundException
493
	 * @throws RemoteInstanceException
494
	 * @throws RemoteNotFoundException
495
	 * @throws RemoteResourceNotFoundException
496
	 * @throws UnknownRemoteException
497
	 * @throws InvalidItemException
498
	 * @throws RequestNetworkException
499
	 * @throws SignatoryException
500
	 */
501
	private function confirmMember(IFederatedUser $member): void {
502
503
		// TODO: confirm SingleId ???
504
//		switch ($member->getUserType()) {
505
//			case Member::TYPE_USER:
506
		$this->federatedUserService->getFederatedUser($member->getUserId(), $member->getUserType());
507
//				break;
508
//
509
//			// TODO: confirm other UserType
510
//			default:
511
//				break;
512
////				throw new UserTypeNotFoundException();
513
//		}
514
	}
515
516
517
	/**
518
	 * @param IFederatedUser $member
519
	 *
520
	 * @throws NoUserException
521
	 */
522
	private function confirmMemberTypeUser(IFederatedUser $member): void {
523
		if ($this->configService->isLocalInstance($member->getInstance())) {
524
			$user = $this->userManager->get($member->getUserId());
525
			if ($user === null) {
526
				throw new NoUserException('user not found');
527
			}
528
529
			$member->setUserId($user->getUID());
530
531
			return;
532
		}
533
534
		// TODO #M002: request the remote instance and check that user exists
535
	}
536
537
//	/**
538
//	 * Verify if a local account is valid.
539
//	 *
540
//	 * @param $ident
541
//	 * @param $type
542
//	 *
543
//	 * @param string $instance
544
//	 *
545
//	 * @throws NoUserException
546
//	 */
547
//	private function verifyIdentLocalMember(&$ident, $type, string $instance = '') {
548
//		if ($type !== DeprecatedMember::TYPE_USER) {
549
//			return;
550
//		}
551
//
552
//		if ($instance === '') {
553
//			try {
554
//				$ident = $this->miscService->getRealUserId($ident);
555
//			} catch (NoUserException $e) {
556
//				throw new NoUserException($this->l10n->t("This user does not exist"));
557
//			}
558
//		}
559
//	}
560
//
561
//
562
//	/**
563
//	 * Verify if a mail have a valid format.
564
//	 *
565
//	 * @param string $ident
566
//	 * @param int $type
567
//	 *
568
//	 * @throws EmailAccountInvalidFormatException
569
//	 */
570
//	private function verifyIdentEmailAddress(string $ident, int $type) {
571
//		if ($type !== DeprecatedMember::TYPE_MAIL) {
572
//			return;
573
//		}
574
//
575
//		if ($this->configService->isAccountOnly()) {
576
//			throw new EmailAccountInvalidFormatException(
577
//				$this->l10n->t('You cannot add a mail address as member of your Circle')
578
//			);
579
//		}
580
//
581
//		if (!filter_var($ident, FILTER_VALIDATE_EMAIL)) {
582
//			throw new EmailAccountInvalidFormatException(
583
//				$this->l10n->t('Email format is not valid')
584
//			);
585
//		}
586
//	}
587
//
588
//
589
//	/**
590
//	 * Verify if a contact exist in current user address books.
591
//	 *
592
//	 * @param $ident
593
//	 * @param $type
594
//	 *
595
//	 * @throws NoUserException
596
//	 * @throws EmailAccountInvalidFormatException
597
//	 */
598
//	private function verifyIdentContact(&$ident, $type) {
599
//		if ($type !== DeprecatedMember::TYPE_CONTACT) {
600
//			return;
601
//		}
602
//
603
//		if ($this->configService->isAccountOnly()) {
604
//			throw new EmailAccountInvalidFormatException(
605
//				$this->l10n->t('You cannot add a contact as member of your Circle')
606
//			);
607
//		}
608
//
609
//		$tmpContact = $this->userId . ':' . $ident;
610
//		$result = MiscService::getContactData($tmpContact);
611
//		if (empty($result)) {
612
//			throw new NoUserException($this->l10n->t("This contact is not available"));
613
//		}
614
//
615
//		$ident = $tmpContact;
616
//	}
617
618
619
	/**
620
	 * @param DeprecatedCircle $circle
621
	 * @param string $recipient
622
	 * @param array $links
623
	 * @param string $password
624
	 */
625 View Code Duplication
	private function memberIsMailbox(
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...
626
		DeprecatedCircle $circle, string $recipient, array $links, string $password
627
	) {
628
		if ($circle->getViewer() === null) {
629
			$author = $circle->getOwner()
630
							 ->getUserId();
631
		} else {
632
			$author = $circle->getViewer()
633
							 ->getUserId();
634
		}
635
636
		try {
637
			$template = $this->generateMailExitingShares($author, $circle->getName());
638
			$this->fillMailExistingShares($template, $links);
639
			$this->sendMailExistingShares($template, $author, $recipient);
640
			$this->sendPasswordExistingShares($author, $recipient, $password);
641
		} catch (Exception $e) {
642
			$this->miscService->log('Failed to send mail about existing share ' . $e->getMessage());
0 ignored issues
show
Bug introduced by
The property miscService does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
643
		}
644
	}
645
646
647
	/**
648
	 * @param DeprecatedCircle $circle
649
	 * @param DeprecatedMember $member
650
	 * @param string $password
651
	 *
652
	 * @return array
653
	 */
654 View Code Duplication
	private function generateUnknownSharesLinks(
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...
655
		DeprecatedCircle $circle, DeprecatedMember $member, string $password
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...
656
	): array {
657
		$unknownShares = $this->getUnknownShares($member);
658
659
		$data = [];
660
		foreach ($unknownShares as $share) {
661
			try {
662
				$data[] = $this->getMailLinkFromShare($share, $member, $password);
663
			} catch (TokenDoesNotExistException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
664
			}
665
		}
666
667
		return $data;
668
	}
669
670
671
	/**
672
	 * @param DeprecatedMember $member
673
	 *
674
	 * @return array
675
	 */
676 View Code Duplication
	private function getUnknownShares(DeprecatedMember $member): 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...
677
		$allShares = $this->fileSharesRequest->getSharesForCircle($member->getCircleId());
0 ignored issues
show
Bug introduced by
The property fileSharesRequest does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
678
		$knownShares = array_map(
679
			function(SharesToken $shareToken) {
680
				return $shareToken->getShareId();
681
			},
682
			$this->tokensRequest->getTokensFromMember($member)
0 ignored issues
show
Bug introduced by
The property tokensRequest does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
683
		);
684
685
		$unknownShares = [];
686
		foreach ($allShares as $share) {
687
			if (!in_array($share['id'], $knownShares)) {
688
				$unknownShares[] = $share;
689
			}
690
		}
691
692
		return $unknownShares;
693
	}
694
695
696
	/**
697
	 * @param array $share
698
	 * @param DeprecatedMember $member
699
	 * @param string $password
700
	 *
701
	 * @return array
702
	 * @throws TokenDoesNotExistException
703
	 */
704 View Code Duplication
	private function getMailLinkFromShare(array $share, DeprecatedMember $member, string $password = '') {
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...
705
		$sharesToken = $this->tokensRequest->generateTokenForMember($member, (int)$share['id'], $password);
706
		$link = $this->urlGenerator->linkToRouteAbsolute(
0 ignored issues
show
Bug introduced by
The property urlGenerator does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
707
			'files_sharing.sharecontroller.showShare',
708
			['token' => $sharesToken->getToken()]
709
		);
710
		$author = $share['uid_initiator'];
711
		$filename = basename($share['file_target']);
712
713
		return [
714
			'author'   => $author,
715
			'link'     => $link,
716
			'filename' => $filename
717
		];
718
	}
719
720
721
	/**
722
	 * @param string $author
723
	 * @param string $circleName
724
	 *
725
	 * @return IEMailTemplate
726
	 */
727 View Code Duplication
	private function generateMailExitingShares(string $author, string $circleName): IEMailTemplate {
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...
728
		$emailTemplate = $this->mailer->createEMailTemplate('circles.ExistingShareNotification', []);
0 ignored issues
show
Bug introduced by
The property mailer does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
729
		$emailTemplate->addHeader();
730
731
		$text = $this->l10n->t('%s shared multiple files with "%s".', [$author, $circleName]);
0 ignored issues
show
Bug introduced by
The property l10n does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
732
		$emailTemplate->addBodyText(htmlspecialchars($text), $text);
733
734
		return $emailTemplate;
735
	}
736
737
	/**
738
	 * @param IEMailTemplate $emailTemplate
739
	 * @param array $links
740
	 */
741 View Code Duplication
	private function fillMailExistingShares(IEMailTemplate $emailTemplate, array $links) {
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...
742
		foreach ($links as $item) {
743
			$emailTemplate->addBodyButton(
744
				$this->l10n->t('Open »%s«', [htmlspecialchars($item['filename'])]), $item['link']
745
			);
746
		}
747
	}
748
749
750
	/**
751
	 * @param IEMailTemplate $emailTemplate
752
	 * @param string $author
753
	 * @param string $recipient
754
	 *
755
	 * @throws Exception
756
	 */
757 View Code Duplication
	private function sendMailExistingShares(IEMailTemplate $emailTemplate, string $author, string $recipient
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...
758
	) {
759
		$subject = $this->l10n->t('%s shared multiple files with you.', [$author]);
760
761
		$instanceName = $this->defaults->getName();
0 ignored issues
show
Bug introduced by
The property defaults does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
762
		$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]);
763
764
		$message = $this->mailer->createMessage();
765
766
		$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]);
767
		$message->setSubject($subject);
768
		$message->setPlainBody($emailTemplate->renderText());
769
		$message->setHtmlBody($emailTemplate->renderHtml());
770
		$message->setTo([$recipient]);
771
772
		$this->mailer->send($message);
773
	}
774
775
776
	/**
777
	 * @param string $author
778
	 * @param string $email
779
	 * @param string $password
780
	 *
781
	 * @throws Exception
782
	 */
783
	protected function sendPasswordExistingShares(string $author, string $email, string $password) {
784
		if ($password === '') {
785
			return;
786
		}
787
788
		$message = $this->mailer->createMessage();
789
790
		$authorUser = $this->userManager->get($author);
791
		$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...
792
		$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...
793
794
		$this->miscService->log("Sending password mail about existing files to '" . $email . "'", 0);
795
796
		$plainBodyPart = $this->l10n->t(
797
			"%1\$s shared multiple files with you.\nYou should have already received a separate mail with a link to access them.\n",
798
			[$authorName]
799
		);
800
		$htmlBodyPart = $this->l10n->t(
801
			'%1$s shared multiple files with you. You should have already received a separate mail with a link to access them.',
802
			[$authorName]
803
		);
804
805
		$emailTemplate = $this->mailer->createEMailTemplate(
806
			'sharebymail.RecipientPasswordNotification', [
807
														   'password' => $password,
808
														   'author'   => $author
809
													   ]
810
		);
811
812
		$emailTemplate->setSubject(
813
			$this->l10n->t(
814
				'Password to access files shared to you by %1$s', [$authorName]
815
			)
816
		);
817
		$emailTemplate->addHeader();
818
		$emailTemplate->addHeading($this->l10n->t('Password to access files'), false);
819
		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
820
		$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:'));
821
		$emailTemplate->addBodyText($password);
822
823
		// The "From" contains the sharers name
824
		$instanceName = $this->defaults->getName();
825
		$senderName = $this->l10n->t(
826
			'%1$s via %2$s',
827
			[
828
				$authorName,
829
				$instanceName
830
			]
831
		);
832
833
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
834
		if ($authorEmail !== null) {
835
			$message->setReplyTo([$authorEmail => $authorName]);
836
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
837
		} else {
838
			$emailTemplate->addFooter();
839
		}
840
841
		$message->setTo([$email]);
842
		$message->useTemplate($emailTemplate);
843
		$this->mailer->send($message);
844
	}
845
846
}
847
848