Completed
Pull Request — master (#625)
by Maxence
02:28
created

SingleMemberAdd::getUnknownShares()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18

Duplication

Lines 18
Ratio 100 %

Importance

Changes 0
Metric Value
dl 18
loc 18
rs 9.6666
c 0
b 0
f 0
cc 3
nc 3
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\TNC22Deserialize;
39
use daita\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Logger;
40
use daita\MySmallPhpTools\Traits\TStringTools;
41
use Exception;
42
use OC\User\NoUserException;
43
use OCA\Circles\Db\MemberRequest;
44
use OCA\Circles\Exceptions\CircleNotFoundException;
45
use OCA\Circles\Exceptions\FederatedItemBadRequestException;
46
use OCA\Circles\Exceptions\FederatedItemException;
47
use OCA\Circles\Exceptions\FederatedItemNotFoundException;
48
use OCA\Circles\Exceptions\FederatedItemRemoteException;
49
use OCA\Circles\Exceptions\FederatedItemServerException;
50
use OCA\Circles\Exceptions\FederatedUserException;
51
use OCA\Circles\Exceptions\FederatedUserNotFoundException;
52
use OCA\Circles\Exceptions\InvalidIdException;
53
use OCA\Circles\Exceptions\MemberNotFoundException;
54
use OCA\Circles\Exceptions\MembersLimitException;
55
use OCA\Circles\Exceptions\OwnerNotFoundException;
56
use OCA\Circles\Exceptions\RemoteInstanceException;
57
use OCA\Circles\Exceptions\RemoteNotFoundException;
58
use OCA\Circles\Exceptions\RemoteResourceNotFoundException;
59
use OCA\Circles\Exceptions\RequestBuilderException;
60
use OCA\Circles\Exceptions\SingleCircleNotFoundException;
61
use OCA\Circles\Exceptions\TokenDoesNotExistException;
62
use OCA\Circles\Exceptions\UnknownRemoteException;
63
use OCA\Circles\Exceptions\UserTypeNotFoundException;
64
use OCA\Circles\IFederatedItem;
65
use OCA\Circles\IFederatedItemAsyncProcess;
66
use OCA\Circles\IFederatedItemHighSeverity;
67
use OCA\Circles\IFederatedItemMemberCheckNotRequired;
68
use OCA\Circles\IFederatedItemMemberRequired;
69
use OCA\Circles\IFederatedUser;
70
use OCA\Circles\Model\Circle;
71
use OCA\Circles\Model\DeprecatedCircle;
72
use OCA\Circles\Model\DeprecatedMember;
73
use OCA\Circles\Model\Federated\FederatedEvent;
74
use OCA\Circles\Model\Federated\RemoteInstance;
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\MemberService;
84
use OCA\Circles\Service\MembershipService;
85
use OCA\Circles\Service\RemoteStreamService;
86
use OCA\Circles\StatusCode;
87
use OCP\IUser;
88
use OCP\IUserManager;
89
use OCP\Mail\IEMailTemplate;
90
use OCP\Util;
91
92
93
/**
94
 * Class MemberAdd
95
 *
96
 * @package OCA\Circles\GlobalScale
97
 */
98
class SingleMemberAdd implements
99
	IFederatedItem,
100
	IFederatedItemAsyncProcess,
101
	IFederatedItemHighSeverity,
102
	IFederatedItemMemberRequired,
103
	IFederatedItemMemberCheckNotRequired {
104
105
106
	use TNC22Deserialize;
107
108
109
	use TStringTools;
110
	use TNC22Logger;
111
112
113
	/** @var IUserManager */
114
	protected $userManager;
115
116
	/** @var MemberRequest */
117
	protected $memberRequest;
118
119
	/** @var FederatedUserService */
120
	protected $federatedUserService;
121
122
	/** @var RemoteStreamService */
123
	protected $remoteStreamService;
124
125
	/** @var CircleService */
126
	protected $circleService;
127
128
	/** @var MemberService */
129
	protected $memberService;
130
131
	/** @var MembershipService */
132
	protected $membershipService;
133
134
	/** @var EventService */
135
	protected $eventService;
136
137
	/** @var ConfigService */
138
	protected $configService;
139
140
141
	/**
142
	 * SingleMemberAdd constructor.
143
	 *
144
	 * @param IUserManager $userManager
145
	 * @param MemberRequest $memberRequest
146
	 * @param FederatedUserService $federatedUserService
147
	 * @param RemoteStreamService $remoteStreamService
148
	 * @param CircleService $circleService
149
	 * @param MemberService $memberService
150
	 * @param MembershipService $membershipService
151
	 * @param EventService $eventService
152
	 * @param ConfigService $configService
153
	 */
154 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...
155
		IUserManager $userManager,
156
		MemberRequest $memberRequest,
157
		FederatedUserService $federatedUserService,
158
		RemoteStreamService $remoteStreamService,
159
		CircleService $circleService,
160
		MemberService $memberService,
161
		MembershipService $membershipService,
162
		EventService $eventService,
163
		ConfigService $configService
164
	) {
165
		$this->userManager = $userManager;
166
		$this->memberRequest = $memberRequest;
167
		$this->federatedUserService = $federatedUserService;
168
		$this->remoteStreamService = $remoteStreamService;
169
		$this->circleService = $circleService;
170
		$this->memberService = $memberService;
171
		$this->membershipService = $membershipService;
172
		$this->eventService = $eventService;
173
		$this->configService = $configService;
174
	}
175
176
177
	/**
178
	 * @param FederatedEvent $event
179
	 *
180
	 * @throws FederatedItemBadRequestException
181
	 * @throws FederatedItemNotFoundException
182
	 * @throws FederatedItemServerException
183
	 * @throws FederatedItemRemoteException
184
	 * @throws FederatedItemException
185
	 * @throws RequestBuilderException
186
	 */
187
	public function verify(FederatedEvent $event): void {
188
		$member = $event->getMember();
189
		$circle = $event->getCircle();
190
		$initiator = $circle->getInitiator();
191
192
		$initiatorHelper = new MemberHelper($initiator);
193
		$initiatorHelper->mustBeModerator();
194
195
		$member = $this->generateMember($event, $circle, $member);
196
197
		$event->setMembers([$member]);
198
		$event->setOutcome($this->serialize($member));
199
200
		return;
201
202
203
//		$member = $this->membersRequest->getFreshNewMember(
204
//			$circle->getUniqueId(), $ident, $eventMember->getType(), $eventMember->getInstance()
205
//		);
206
//		$member->hasToBeInviteAble()
207
//
208
//		$this->membersService->addMemberBasedOnItsType($circle, $member);
209
//
210
//		$password = '';
211
//		$sendPasswordByMail = false;
212
//		if ($this->configService->enforcePasswordProtection($circle)) {
213
//			if ($circle->getSetting('password_single_enabled') === 'true') {
214
//				$password = $circle->getPasswordSingle();
215
//			} else {
216
//				$sendPasswordByMail = true;
217
//				$password = $this->miscService->token(15);
218
//			}
219
//		}
220
//
221
//		$event->setData(
222
//			new SimpleDataStore(
223
//				[
224
//					'password'       => $password,
225
//					'passwordByMail' => $sendPasswordByMail
226
//				]
227
//			)
228
//		);
229
	}
230
231
232
	/**
233
	 * @param FederatedEvent $event
234
	 *
235
	 * @throws InvalidIdException
236
	 * @throws RemoteNotFoundException
237
	 * @throws RequestBuilderException
238
	 * @throws UnknownRemoteException
239
	 */
240 View Code Duplication
	public function manage(FederatedEvent $event): void {
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...
241
		$member = $event->getMember();
242
		if (!$this->memberService->insertOrUpdate($member)) {
243
			return;
244
		}
245
246
		if ($member->getStatus() === Member::STATUS_INVITED) {
247
			$this->eventService->memberInviting($event);
248
		} else {
249
			$this->eventService->memberAdding($event);
250
		}
251
252
//
253
//		//
254
//		// TODO: verifiez comment se passe le cached name sur un member_add
255
//		//
256
//		$cachedName = $member->getCachedName();
257
//		$password = $event->getData()
258
//						  ->g('password');
259
//
260
//		$shares = $this->generateUnknownSharesLinks($circle, $member, $password);
261
//		$result = [
262
//			'unknownShares' => $shares,
263
//			'cachedName'    => $cachedName
264
//		];
265
//
266
//		if ($member->getType() === DeprecatedMember::TYPE_CONTACT
267
//			&& $this->configService->isLocalInstance($member->getInstance())) {
268
//			$result['contact'] = $this->miscService->getInfosFromContact($member);
269
//		}
270
//
271
//		$event->setResult(new SimpleDataStore($result));
272
//		$this->eventsService->onMemberNew($circle, $member);
273
	}
274
275
276
	/**
277
	 * @param FederatedEvent $event
278
	 * @param array $results
279
	 */
280 View Code Duplication
	public function result(FederatedEvent $event, array $results): void {
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...
281
		$member = $event->getMember();
282
		if ($member->getStatus() === Member::STATUS_INVITED) {
283
			$this->eventService->memberInvited($event, $results);
284
		} else {
285
			$this->eventService->memberAdded($event, $results);
286
		}
287
288
//		$password = $cachedName = '';
289
//		$circle = $member = null;
290
//		$links = [];
291
//		$recipients = [];
292
//		foreach ($events as $event) {
293
//			$data = $event->getData();
294
//			if ($data->gBool('passwordByMail') !== false) {
295
//				$password = $data->g('password');
296
//			}
297
//			$circle = $event->getDeprecatedCircle();
298
//			$member = $event->getMember();
299
//			$result = $event->getResult();
300
//			if ($result->g('cachedName') !== '') {
301
//				$cachedName = $result->g('cachedName');
302
//			}
303
//
304
//			$links = array_merge($links, $result->gArray('unknownShares'));
305
//			$contact = $result->gArray('contact');
306
//			if (!empty($contact)) {
307
//				$recipients = $contact['emails'];
308
//			}
309
//		}
310
//
311
//		if (empty($links) || $circle === null || $member === null) {
312
//			return;
313
//		}
314
//
315
//		if ($cachedName !== '') {
316
//			$member->setCachedName($cachedName);
317
//			$this->membersService->updateMember($member);
318
//		}
319
//
320
//		if ($member->getType() === DeprecatedMember::TYPE_MAIL
321
//			|| $member->getType() === DeprecatedMember::TYPE_CONTACT) {
322
//			if ($member->getType() === DeprecatedMember::TYPE_MAIL) {
323
//				$recipients = [$member->getUserId()];
324
//			}
325
//
326
//			foreach ($recipients as $recipient) {
327
//				$this->memberIsMailbox($circle, $recipient, $links, $password);
328
//			}
329
//		}
330
	}
331
332
333
	/**
334
	 * @param FederatedEvent $event
335
	 * @param Circle $circle
336
	 * @param Member $member
337
	 *
338
	 * @return Member
339
	 * @throws CircleNotFoundException
340
	 * @throws FederatedItemBadRequestException
341
	 * @throws FederatedItemException
342
	 * @throws FederatedUserException
343
	 * @throws FederatedUserNotFoundException
344
	 * @throws InvalidIdException
345
	 * @throws MembersLimitException
346
	 * @throws OwnerNotFoundException
347
	 * @throws RemoteInstanceException
348
	 * @throws RemoteNotFoundException
349
	 * @throws RemoteResourceNotFoundException
350
	 * @throws SingleCircleNotFoundException
351
	 * @throws UnknownRemoteException
352
	 * @throws UserTypeNotFoundException
353
	 * @throws RequestBuilderException
354
	 */
355
	protected function generateMember(FederatedEvent $event, Circle $circle, Member $member): Member {
356
		try {
357
			if ($member->getSingleId() !== '') {
358
				$userId = $member->getSingleId() . '@' . $member->getInstance();
359
				$federatedUser = $this->federatedUserService->getFederatedUser($userId, Member::TYPE_SINGLE);
360
361
			} else {
362
				$userId = $member->getUserId() . '@' . $member->getInstance();
363
				$federatedUser = $this->federatedUserService->getFederatedUser(
364
					$userId,
365
					$member->getUserType()
366
				);
367
			}
368
369
		} catch (MemberNotFoundException $e) {
370
			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...
371
		}
372
373
		if ($federatedUser->getBasedOn()->isConfig(Circle::CFG_ROOT)) {
374
			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...
375
		}
376
377
		if ($member->getSingleId() === $circle->getSingleId()) {
378
			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...
379
		}
380
381
		if (!$this->configService->isLocalInstance($member->getInstance())) {
382
			if ($circle->isConfig(Circle::CFG_LOCAL)) {
383
				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...
384
			}
385
386
			if (!$circle->isConfig(Circle::CFG_FEDERATED)) {
387
				$remoteInstance = $this->remoteStreamService->getCachedRemoteInstance($member->getInstance());
388
				if ($remoteInstance->getType() !== RemoteInstance::TYPE_GLOBALSCALE) {
389
					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...
390
				}
391
			}
392
		}
393
394
		$member->importFromIFederatedUser($federatedUser);
395
		$member->setCircleId($circle->getSingleId());
396
		$member->setCircle($circle);
397
398
		$this->confirmPatron($event, $member);
399
		$this->manageMemberStatus($circle, $member);
400
401
		$this->circleService->confirmCircleNotFull($circle);
402
403
		// The idea is that adding the member during the self::verify() will help during the broadcasting
404
		// of the event to Federated RemoteInstance for their first member.
405
		$this->memberRequest->insertOrUpdate($member);
406
407
		return $member;
408
	}
409
410
411
	/**
412
	 * @param Circle $circle
413
	 * @param Member $member
414
	 *
415
	 * @throws FederatedItemBadRequestException
416
	 * @throws RequestBuilderException
417
	 */
418
	private function manageMemberStatus(Circle $circle, Member $member) {
419
		try {
420
			$knownMember = $this->memberRequest->searchMember($member);
421
			$member->setId($knownMember->getId());
422
423
			if ($knownMember->getLevel() === Member::LEVEL_NONE) {
424
				switch ($knownMember->getStatus()) {
425
					case Member::STATUS_BLOCKED:
426
						if ($circle->isConfig(Circle::CFG_INVITE)) {
427
							$member->setStatus(Member::STATUS_INVITED);
428
						}
429
430
						return;
431
432
					case Member::STATUS_REQUEST:
433
						$member->setLevel(Member::LEVEL_MEMBER);
434
						$member->setStatus(Member::STATUS_MEMBER);
435
436
						return;
437
438
					case Member::STATUS_INVITED:
439
						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...
440
				}
441
			}
442
443
			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...
444
		} catch (MemberNotFoundException $e) {
445
			$member->setId($this->token(ManagedModel::ID_LENGTH));
446
447 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...
448
				$member->setStatus(Member::STATUS_INVITED);
449
			} else {
450
				$member->setLevel(Member::LEVEL_MEMBER);
451
				$member->setStatus(Member::STATUS_MEMBER);
452
			}
453
		}
454
	}
455
456
457
	/**
458
	 * @param FederatedEvent $event
459
	 * @param Member $member
460
	 *
461
	 * @throws FederatedItemBadRequestException
462
	 * @throws FederatedUserException
463
	 * @throws RemoteNotFoundException
464
	 * @throws RequestBuilderException
465
	 * @throws UnknownRemoteException
466
	 */
467
	private function confirmPatron(FederatedEvent $event, Member $member): void {
468
		if (!$member->hasInvitedBy()) {
469
			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...
470
		}
471
472
		$patron = $member->getInvitedBy();
473
		if ($patron->getInstance() !== $event->getSender()) {
474
			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...
475
		}
476
477
		$this->federatedUserService->confirmSingleIdUniqueness($patron);
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 email 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 email 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 email 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