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

SingleMemberAdd::verify()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 43
rs 9.232
c 0
b 0
f 0
cc 1
nc 1
nop 1
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
		if ($patron->getInstance() !== $event->getOrigin()) {
451
			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...
452
		}
453
454
		$this->federatedUserService->confirmLocalSingleId($patron);
455
	}
456
457
458
	/**
459
	 * @param Member $member
460
	 *
461
	 * @return bool
462
	 * @throws InvalidIdException
463
	 */
464
	private function insertOrUpdate(Member $member): bool {
465
		try {
466
			$federatedUser = new FederatedUser();
467
			$federatedUser->importFromIFederatedUser($member);
468
			$this->federatedUserService->confirmLocalSingleId($federatedUser);
469
		} catch (FederatedUserException $e) {
470
			$this->e($e, ['member' => $member]);
471
472
			return false;
473
		}
474
475
		$this->memberRequest->insertOrUpdate($member);
476
477
		return true;
478
	}
479
480
481
	/**
482
	 * confirm the validity of a UserId, based on UserType.
483
	 *
484
	 * @param IFederatedUser $member
485
	 *
486
	 * @throws FederatedUserException
487
	 * @throws InvalidIdException
488
	 * @throws UserTypeNotFoundException
489
	 * @throws CircleNotFoundException
490
	 * @throws FederatedUserNotFoundException
491
	 * @throws OwnerNotFoundException
492
	 * @throws RemoteInstanceException
493
	 * @throws RemoteNotFoundException
494
	 * @throws RemoteResourceNotFoundException
495
	 * @throws UnknownRemoteException
496
	 * @throws InvalidItemException
497
	 * @throws RequestNetworkException
498
	 * @throws SignatoryException
499
	 */
500
	private function confirmMember(IFederatedUser $member): void {
501
502
		// TODO: confirm SingleId ???
503
//		switch ($member->getUserType()) {
504
//			case Member::TYPE_USER:
505
		$this->federatedUserService->getFederatedUser($member->getUserId(), $member->getUserType());
506
//				break;
507
//
508
//			// TODO: confirm other UserType
509
//			default:
510
//				break;
511
////				throw new UserTypeNotFoundException();
512
//		}
513
	}
514
515
516
	/**
517
	 * @param IFederatedUser $member
518
	 *
519
	 * @throws NoUserException
520
	 */
521
	private function confirmMemberTypeUser(IFederatedUser $member): void {
522
		if ($this->configService->isLocalInstance($member->getInstance())) {
523
			$user = $this->userManager->get($member->getUserId());
524
			if ($user === null) {
525
				throw new NoUserException('user not found');
526
			}
527
528
			$member->setUserId($user->getUID());
529
530
			return;
531
		}
532
533
		// TODO #M002: request the remote instance and check that user exists
534
	}
535
536
//	/**
537
//	 * Verify if a local account is valid.
538
//	 *
539
//	 * @param $ident
540
//	 * @param $type
541
//	 *
542
//	 * @param string $instance
543
//	 *
544
//	 * @throws NoUserException
545
//	 */
546
//	private function verifyIdentLocalMember(&$ident, $type, string $instance = '') {
547
//		if ($type !== DeprecatedMember::TYPE_USER) {
548
//			return;
549
//		}
550
//
551
//		if ($instance === '') {
552
//			try {
553
//				$ident = $this->miscService->getRealUserId($ident);
554
//			} catch (NoUserException $e) {
555
//				throw new NoUserException($this->l10n->t("This user does not exist"));
556
//			}
557
//		}
558
//	}
559
//
560
//
561
//	/**
562
//	 * Verify if a mail have a valid format.
563
//	 *
564
//	 * @param string $ident
565
//	 * @param int $type
566
//	 *
567
//	 * @throws EmailAccountInvalidFormatException
568
//	 */
569
//	private function verifyIdentEmailAddress(string $ident, int $type) {
570
//		if ($type !== DeprecatedMember::TYPE_MAIL) {
571
//			return;
572
//		}
573
//
574
//		if ($this->configService->isAccountOnly()) {
575
//			throw new EmailAccountInvalidFormatException(
576
//				$this->l10n->t('You cannot add a mail address as member of your Circle')
577
//			);
578
//		}
579
//
580
//		if (!filter_var($ident, FILTER_VALIDATE_EMAIL)) {
581
//			throw new EmailAccountInvalidFormatException(
582
//				$this->l10n->t('Email format is not valid')
583
//			);
584
//		}
585
//	}
586
//
587
//
588
//	/**
589
//	 * Verify if a contact exist in current user address books.
590
//	 *
591
//	 * @param $ident
592
//	 * @param $type
593
//	 *
594
//	 * @throws NoUserException
595
//	 * @throws EmailAccountInvalidFormatException
596
//	 */
597
//	private function verifyIdentContact(&$ident, $type) {
598
//		if ($type !== DeprecatedMember::TYPE_CONTACT) {
599
//			return;
600
//		}
601
//
602
//		if ($this->configService->isAccountOnly()) {
603
//			throw new EmailAccountInvalidFormatException(
604
//				$this->l10n->t('You cannot add a contact as member of your Circle')
605
//			);
606
//		}
607
//
608
//		$tmpContact = $this->userId . ':' . $ident;
609
//		$result = MiscService::getContactData($tmpContact);
610
//		if (empty($result)) {
611
//			throw new NoUserException($this->l10n->t("This contact is not available"));
612
//		}
613
//
614
//		$ident = $tmpContact;
615
//	}
616
617
618
	/**
619
	 * @param DeprecatedCircle $circle
620
	 * @param string $recipient
621
	 * @param array $links
622
	 * @param string $password
623
	 */
624 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...
625
		DeprecatedCircle $circle, string $recipient, array $links, string $password
626
	) {
627
		if ($circle->getViewer() === null) {
628
			$author = $circle->getOwner()
629
							 ->getUserId();
630
		} else {
631
			$author = $circle->getViewer()
632
							 ->getUserId();
633
		}
634
635
		try {
636
			$template = $this->generateMailExitingShares($author, $circle->getName());
637
			$this->fillMailExistingShares($template, $links);
638
			$this->sendMailExistingShares($template, $author, $recipient);
639
			$this->sendPasswordExistingShares($author, $recipient, $password);
640
		} catch (Exception $e) {
641
			$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...
642
		}
643
	}
644
645
646
	/**
647
	 * @param DeprecatedCircle $circle
648
	 * @param DeprecatedMember $member
649
	 * @param string $password
650
	 *
651
	 * @return array
652
	 */
653 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...
654
		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...
655
	): array {
656
		$unknownShares = $this->getUnknownShares($member);
657
658
		$data = [];
659
		foreach ($unknownShares as $share) {
660
			try {
661
				$data[] = $this->getMailLinkFromShare($share, $member, $password);
662
			} catch (TokenDoesNotExistException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
663
			}
664
		}
665
666
		return $data;
667
	}
668
669
670
	/**
671
	 * @param DeprecatedMember $member
672
	 *
673
	 * @return array
674
	 */
675 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...
676
		$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...
677
		$knownShares = array_map(
678
			function(SharesToken $shareToken) {
679
				return $shareToken->getShareId();
680
			},
681
			$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...
682
		);
683
684
		$unknownShares = [];
685
		foreach ($allShares as $share) {
686
			if (!in_array($share['id'], $knownShares)) {
687
				$unknownShares[] = $share;
688
			}
689
		}
690
691
		return $unknownShares;
692
	}
693
694
695
	/**
696
	 * @param array $share
697
	 * @param DeprecatedMember $member
698
	 * @param string $password
699
	 *
700
	 * @return array
701
	 * @throws TokenDoesNotExistException
702
	 */
703 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...
704
		$sharesToken = $this->tokensRequest->generateTokenForMember($member, (int)$share['id'], $password);
705
		$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...
706
			'files_sharing.sharecontroller.showShare',
707
			['token' => $sharesToken->getToken()]
708
		);
709
		$author = $share['uid_initiator'];
710
		$filename = basename($share['file_target']);
711
712
		return [
713
			'author'   => $author,
714
			'link'     => $link,
715
			'filename' => $filename
716
		];
717
	}
718
719
720
	/**
721
	 * @param string $author
722
	 * @param string $circleName
723
	 *
724
	 * @return IEMailTemplate
725
	 */
726 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...
727
		$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...
728
		$emailTemplate->addHeader();
729
730
		$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...
731
		$emailTemplate->addBodyText(htmlspecialchars($text), $text);
732
733
		return $emailTemplate;
734
	}
735
736
	/**
737
	 * @param IEMailTemplate $emailTemplate
738
	 * @param array $links
739
	 */
740 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...
741
		foreach ($links as $item) {
742
			$emailTemplate->addBodyButton(
743
				$this->l10n->t('Open »%s«', [htmlspecialchars($item['filename'])]), $item['link']
744
			);
745
		}
746
	}
747
748
749
	/**
750
	 * @param IEMailTemplate $emailTemplate
751
	 * @param string $author
752
	 * @param string $recipient
753
	 *
754
	 * @throws Exception
755
	 */
756 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...
757
	) {
758
		$subject = $this->l10n->t('%s shared multiple files with you.', [$author]);
759
760
		$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...
761
		$senderName = $this->l10n->t('%s on %s', [$author, $instanceName]);
762
763
		$message = $this->mailer->createMessage();
764
765
		$message->setFrom([Util::getDefaultEmailAddress($instanceName) => $senderName]);
766
		$message->setSubject($subject);
767
		$message->setPlainBody($emailTemplate->renderText());
768
		$message->setHtmlBody($emailTemplate->renderHtml());
769
		$message->setTo([$recipient]);
770
771
		$this->mailer->send($message);
772
	}
773
774
775
	/**
776
	 * @param string $author
777
	 * @param string $email
778
	 * @param string $password
779
	 *
780
	 * @throws Exception
781
	 */
782
	protected function sendPasswordExistingShares(string $author, string $email, string $password) {
783
		if ($password === '') {
784
			return;
785
		}
786
787
		$message = $this->mailer->createMessage();
788
789
		$authorUser = $this->userManager->get($author);
790
		$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...
791
		$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...
792
793
		$this->miscService->log("Sending password mail about existing files to '" . $email . "'", 0);
794
795
		$plainBodyPart = $this->l10n->t(
796
			"%1\$s shared multiple files with you.\nYou should have already received a separate mail with a link to access them.\n",
797
			[$authorName]
798
		);
799
		$htmlBodyPart = $this->l10n->t(
800
			'%1$s shared multiple files with you. You should have already received a separate mail with a link to access them.',
801
			[$authorName]
802
		);
803
804
		$emailTemplate = $this->mailer->createEMailTemplate(
805
			'sharebymail.RecipientPasswordNotification', [
806
														   'password' => $password,
807
														   'author'   => $author
808
													   ]
809
		);
810
811
		$emailTemplate->setSubject(
812
			$this->l10n->t(
813
				'Password to access files shared to you by %1$s', [$authorName]
814
			)
815
		);
816
		$emailTemplate->addHeader();
817
		$emailTemplate->addHeading($this->l10n->t('Password to access files'), false);
818
		$emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart);
819
		$emailTemplate->addBodyText($this->l10n->t('It is protected with the following password:'));
820
		$emailTemplate->addBodyText($password);
821
822
		// The "From" contains the sharers name
823
		$instanceName = $this->defaults->getName();
824
		$senderName = $this->l10n->t(
825
			'%1$s via %2$s',
826
			[
827
				$authorName,
828
				$instanceName
829
			]
830
		);
831
832
		$message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]);
833
		if ($authorEmail !== null) {
834
			$message->setReplyTo([$authorEmail => $authorName]);
835
			$emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan());
836
		} else {
837
			$emailTemplate->addFooter();
838
		}
839
840
		$message->setTo([$email]);
841
		$message->useTemplate($emailTemplate);
842
		$this->mailer->send($message);
843
	}
844
845
}
846
847