Completed
Push — master ( f9a32b...1fc0d2 )
by Maxence
04:23
created

FederatedLinkService::parseRequestLinkError()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 17
rs 9.4285
c 1
b 0
f 0
cc 2
eloc 11
nc 2
nop 1
1
<?php
2
/**
3
 * Circles - Bring cloud-users closer together.
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Maxence Lange <[email protected]>
9
 * @copyright 2017
10
 * @license GNU AGPL version 3 or any later version
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License as
14
 * published by the Free Software Foundation, either version 3 of the
15
 * License, or (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
 *
25
 */
26
27
namespace OCA\Circles\Service;
28
29
30
use Exception;
31
use OCA\Circles\Api\v1\Circles;
32
use OCA\Circles\AppInfo\Application;
33
use OCA\Circles\Db\CirclesRequest;
34
use OCA\Circles\Db\FederatedLinksRequest;
35
use OCA\Circles\Exceptions\CircleTypeNotValidException;
36
use OCA\Circles\Exceptions\FederatedCircleLinkFormatException;
37
use OCA\Circles\Exceptions\FederatedCircleNotAllowedException;
38
use OCA\Circles\Exceptions\FederatedCircleStatusUpdateException;
39
use OCA\Circles\Exceptions\FederatedLinkCreationException;
40
use OCA\Circles\Exceptions\FederatedLinkDoesNotExistException;
41
use OCA\Circles\Exceptions\FederatedLinkUpdateException;
42
use OCA\Circles\Exceptions\FederatedRemoteCircleDoesNotExistException;
43
use OCA\Circles\Exceptions\FederatedRemoteDoesNotAllowException;
44
use OCA\Circles\Exceptions\FederatedRemoteIsDownException;
45
use OCA\Circles\Exceptions\MemberIsNotAdminException;
46
use OCA\Circles\Model\Circle;
47
use OCA\Circles\Model\FederatedLink;
48
use OCP\Http\Client\IClientService;
49
use OCP\IL10N;
50
51
class FederatedLinkService {
52
53
	/** @var string */
54
	private $userId;
55
56
	/** @var IL10N */
57
	private $l10n;
58
59
	/** @var CirclesRequest */
60
	private $circlesRequest;
61
62
	/** @var ConfigService */
63
	private $configService;
64
65
	/** @var CirclesService */
66
	private $circlesService;
67
68
	/** @var BroadcastService */
69
	private $broadcastService;
70
71
	/** @var FederatedLinksRequest */
72
	private $federatedLinksRequest;
73
74
	/** @var EventsService */
75
	private $eventsService;
76
77
	/** @var IClientService */
78
	private $clientService;
79
80
	/** @var MiscService */
81
	private $miscService;
82
83
84
	/**
85
	 * FederatedLinkService constructor.
86
	 *
87
	 * @param string $UserId
88
	 * @param IL10N $l10n
89
	 * @param CirclesRequest $circlesRequest
90
	 * @param ConfigService $configService
91
	 * @param CirclesService $circlesService
92
	 * @param BroadcastService $broadcastService
93
	 * @param FederatedLinksRequest $federatedLinksRequest
94
	 * @param EventsService $eventsService
95
	 * @param IClientService $clientService
96
	 * @param MiscService $miscService
97
	 */
98
	public function __construct(
0 ignored issues
show
Coding Style Naming introduced by
The parameter $UserId is not named in camelCase.

This check marks parameter names that have not been written in camelCase.

In camelCase names are written without any punctuation, the start of each new word being marked by a capital letter. Thus the name database connection string becomes databaseConnectionString.

Loading history...
99
		$UserId, IL10N $l10n, CirclesRequest $circlesRequest, ConfigService $configService,
100
		CirclesService $circlesService, BroadcastService $broadcastService,
101
		FederatedLinksRequest $federatedLinksRequest, EventsService $eventsService,
102
		IClientService $clientService, MiscService $miscService
103
	) {
104
		$this->userId = $UserId;
105
		$this->l10n = $l10n;
106
		$this->circlesRequest = $circlesRequest;
107
		$this->configService = $configService;
108
		$this->circlesService = $circlesService;
109
		$this->broadcastService = $broadcastService;
110
		$this->federatedLinksRequest = $federatedLinksRequest;
111
		$this->eventsService = $eventsService;
112
113
		$this->clientService = $clientService;
114
		$this->miscService = $miscService;
115
	}
116
117
118
	/**
119
	 * linkCircle();
120
	 *
121
	 * link to a circle.
122
	 * Function will check if settings allow Federated links between circles, and the format of
123
	 * the link ($remote). If no exception, a request to the remote circle will be initiated
124
	 * using requestLinkWithCircle()
125
	 *
126
	 * $remote format: <circle_name>@<remote_host>
127
	 *
128
	 * @param string $circleUniqueId
129
	 * @param string $remote
130
	 *
131
	 * @throws Exception
132
	 * @throws FederatedCircleLinkFormatException
133
	 * @throws CircleTypeNotValidException
134
	 *
135
	 * @return FederatedLink
136
	 */
137
	public function linkCircle($circleUniqueId, $remote) {
138
139
		if (!$this->configService->isFederatedCirclesAllowed()) {
140
			throw new FederatedCircleNotAllowedException(
141
				$this->l10n->t("Federated circles are not allowed on this Nextcloud")
142
			);
143
		}
144
145
		if (strpos($remote, '@') === false) {
146
			throw new FederatedCircleLinkFormatException(
147
				$this->l10n->t("Federated link does not have a valid format")
148
			);
149
		}
150
151
		try {
152
			return $this->requestLinkWithCircle($circleUniqueId, $remote);
153
		} catch (Exception $e) {
154
			throw $e;
155
		}
156
	}
157
158
159
	/**
160
	 * linkStatus()
161
	 *
162
	 * Update the status of a link.
163
	 * Function will check if user can edit the status, will update it and send the update to
164
	 * remote
165
	 *
166
	 * @param string $linkUniqueId
167
	 * @param int $status
168
	 *
169
	 * @throws Exception
170
	 * @throws FederatedCircleLinkFormatException
171
	 * @throws CircleTypeNotValidException
172
	 * @throws MemberIsNotAdminException
173
	 *
174
	 * @return FederatedLink[]
175
	 */
176
	public function linkStatus($linkUniqueId, $status) {
177
178
		$status = (int)$status;
179
		$link = null;
180
		try {
181
182
			$link = $this->federatedLinksRequest->getLinkFromId($linkUniqueId);
183
			$circle = $this->circlesRequest->getCircle($link->getCircleId(), $this->userId);
184
			$circle->hasToBeFederated();
185
			$circle->getHigherViewer()
186
				   ->hasToBeAdmin();
187
			$link->hasToBeValidStatusUpdate($status);
188
189
			if (!$this->eventOnLinkStatus($circle, $link, $status)) {
190
				return $this->federatedLinksRequest->getLinksFromCircle($circle->getUniqueId());
191
			}
192
193
		} catch (Exception $e) {
194
			throw $e;
195
		}
196
197
		$link->setStatus($status);
198
		$link->setCircleId($circle->getUniqueId(true));
199
200
		try {
201
			$this->updateLinkRemote($link);
202
		} catch (Exception $e) {
203
			if ($status !== FederatedLink::STATUS_LINK_REMOVE) {
204
				throw $e;
205
			}
206
		}
207
208
		$this->federatedLinksRequest->update($link);
209
210
		return $this->federatedLinksRequest->getLinksFromCircle($circle->getUniqueId());
211
	}
212
213
214
	/**
215
	 * eventOnLinkStatus();
216
	 *
217
	 * Called by linkStatus() to manage events when status is changing.
218
	 * If status does not need update, returns false;
219
	 *
220
	 * @param Circle $circle
221
	 * @param FederatedLink $link
222
	 * @param $status
223
	 *
224
	 * @return bool
225
	 */
226
	private function eventOnLinkStatus(Circle $circle, FederatedLink $link, $status) {
227
		if ($link->getStatus() === $status) {
228
			return false;
229
		}
230
231
		if ($status === FederatedLink::STATUS_LINK_REMOVE) {
232
			$this->eventsService->onLinkRemove($circle, $link);
233
		}
234
235
		if ($status === FederatedLink::STATUS_LINK_UP) {
236
			$this->eventsService->onLinkRequestAccepting($circle, $link);
237
			$this->eventsService->onLinkUp($circle, $link);
238
		}
239
240
		return true;
241
	}
242
243
244
	/**
245
	 * requestLinkWithCircle()
246
	 *
247
	 * Using CircleId, function will get more infos from the database.
248
	 * Will check if author is at least admin and initiate a FederatedLink, save it
249
	 * in the database and send a request to the remote circle using requestLink()
250
	 * If any issue, entry is removed from the database.
251
	 *
252
	 * @param string $circleUniqueId
253
	 * @param string $remote
254
	 *
255
	 * @return FederatedLink
256
	 * @throws Exception
257
	 */
258
	private function requestLinkWithCircle($circleUniqueId, $remote) {
259
260
		$link = null;
261
		try {
262
			$circle = $this->circlesService->detailsCircle($circleUniqueId);
263
			$circle->getHigherViewer()
264
				   ->hasToBeAdmin();
265
			$circle->hasToBeFederated();
266
			$circle->cantBePersonal();
267
268
			$link = $this->generateNewLinkWithRemoteCircle($circle->getUniqueId(), $remote);
269
			$this->requestLink($circle, $link);
270
		} catch (Exception $e) {
271
			$this->federatedLinksRequest->delete($link);
0 ignored issues
show
Bug introduced by
It seems like $link defined by null on line 260 can be null; however, OCA\Circles\Db\FederatedLinksRequest::delete() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
272
			throw $e;
273
		}
274
275
		return $link;
276
	}
277
278
279
	/**
280
	 * @param $circleUniqueId
281
	 * @param $remote
282
	 *
283
	 * @return FederatedLink
284
	 */
285
	private function generateNewLinkWithRemoteCircle($circleUniqueId, $remote) {
286
287
		$link = new FederatedLink();
288
		list($remoteCircle, $remoteAddress) = explode('@', $remote, 2);
289
290
		$link->setCircleId($circleUniqueId)
291
			 ->setLocalAddress($this->configService->getLocalAddress())
292
			 ->setAddress($remoteAddress)
293
			 ->setRemoteCircleName($remoteCircle)
294
			 ->setStatus(FederatedLink::STATUS_LINK_SETUP)
295
			 ->generateToken();
296
297
		$this->federatedLinksRequest->create($link);
298
299
		return $link;
300
	}
301
302
303
	/**
304
	 * @param string $remote
305
	 *
306
	 * @return string
307
	 */
308
	private function generateLinkRemoteURL($remote) {
309
		return $this->configService->generateRemoteHost($remote) . Application::REMOTE_URL_LINK;
310
	}
311
312
313
	/**
314
	 * requestLink()
315
	 *
316
	 *
317
	 * @param Circle $circle
318
	 * @param FederatedLink $link
319
	 *
320
	 * @return boolean
321
	 * @throws Exception
322
	 */
323
	private function requestLink(Circle $circle, FederatedLink &$link) {
324
		$args = [
325
			'apiVersion' => Circles::version(),
326
			'token'      => $link->getToken(true),
327
			'uniqueId'   => $circle->getUniqueId(true),
328
			'sourceName' => $circle->getName(),
329
			'linkTo'     => $link->getRemoteCircleName(),
330
			'address'    => $link->getLocalAddress()
331
		];
332
333
		$client = $this->clientService->newClient();
334
335
		try {
336
			$request = $client->put(
337
				$this->generateLinkRemoteURL($link->getAddress()), [
338
																	 'body'            => $args,
339
																	 'timeout'         => 10,
340
																	 'connect_timeout' => 10,
341
																 ]
342
			);
343
344
			$result = json_decode($request->getBody(), true);
345
			if ($result === null) {
346
				throw new FederatedRemoteIsDownException(
347
					$this->l10n->t(
348
						'The remote host is down or the Circles app is not installed on it'
349
					)
350
				);
351
			}
352
353
			$this->eventOnRequestLink(
354
				$circle, $link, $result['status'],
355
				((key_exists('reason', $result)) ? $result['reason'] : '')
356
			);
357
358
			$link->setUniqueId($result['uniqueId']);
359
			$this->federatedLinksRequest->update($link);
360
361
			return true;
362
		} catch (Exception $e) {
363
			throw $e;
364
		}
365
	}
366
367
368
	/**
369
	 * eventOnRequestLink();
370
	 *
371
	 * Called by requestLink() will update status and event
372
	 * Will also manage errors returned by the remote link
373
	 *
374
	 * @param Circle $circle
375
	 * @param FederatedLink $link
376
	 * @param $status
377
	 * @param $reason
378
	 *
379
	 * @throws Exception
380
	 */
381
	private function eventOnRequestLink(Circle $circle, FederatedLink $link, $status, $reason) {
382
383
		try {
384
			if ($status === FederatedLink::STATUS_LINK_UP) {
385
				$link->setStatus(FederatedLink::STATUS_LINK_UP);
386
				$this->eventsService->onLinkUp($circle, $link);
387
			} else if ($status === FederatedLink::STATUS_LINK_REQUESTED) {
388
				$link->setStatus(FederatedLink::STATUS_REQUEST_SENT);
389
				$this->eventsService->onLinkRequestSent($circle, $link);
390
			} else {
391
				$this->parseRequestLinkError($reason);
392
			}
393
		} catch (Exception $e) {
394
			throw $e;
395
		}
396
	}
397
398
399
	/**
400
	 * parseRequestLinkError();
401
	 *
402
	 * Will parse the error reason returned by requestLink() and throw an Exception
403
	 *
404
	 * @param $reason
405
	 *
406
	 * @throws Exception
407
	 * @throws FederatedRemoteCircleDoesNotExistException
408
	 * @throws FederatedRemoteDoesNotAllowException
409
	 */
410
	private function parseRequestLinkError($reason) {
411
412
		$convert = [
413
			'federated_not_allowed' => $this->l10n->t(
414
				'Federated circles are not allowed on the remote Nextcloud'
415
			),
416
			'circle_links_disable'  => $this->l10n->t('Remote circle does not accept federated links'),
417
			'duplicate_unique_id'   => $this->l10n->t('Trying to link a circle to itself'),
418
			'duplicate_link'        => $this->l10n->t('This link exists already'),
419
			'circle_does_not_exist' => $this->l10n->t('The requested remote circle does not exist')
420
		];
421
422
		if (key_exists($reason, $convert)) {
423
			throw new FederatedRemoteDoesNotAllowException($convert[$reason]);
424
		}
425
		throw new Exception($reason);
426
	}
427
428
429
	/**
430
	 * @param string $token
431
	 * @param string $uniqueId
432
	 * @param int $status
433
	 *
434
	 * @return FederatedLink
435
	 * @throws Exception
436
	 */
437
	public function updateLinkFromRemote($token, $uniqueId, $status) {
438
		try {
439
			$link = $this->federatedLinksRequest->getLinkFromToken($token, $uniqueId);
440
			$circle = $this->circlesRequest->forceGetCircle($link->getCircleId());
441
			$circle->hasToBeFederated();
442
443
			$this->checkUpdateLinkFromRemote($status);
444
			$this->checkUpdateLinkFromRemoteLinkUp($circle, $link, $status);
445
			$this->checkUpdateLinkFromRemoteLinkRemove($circle, $link, $status);
446
447
			if ($link->getStatus() !== $status) {
448
				$this->federatedLinksRequest->update($link);
449
			}
450
451
			return $link;
452
		} catch (Exception $e) {
453
			throw $e;
454
		}
455
	}
456
457
	/**
458
	 * checkUpdateLinkFromRemote();
459
	 *
460
	 * will throw exception is the status sent by remote is not correct
461
	 *
462
	 * @param int $status
463
	 *
464
	 * @throws FederatedCircleStatusUpdateException
465
	 */
466
	private function checkUpdateLinkFromRemote($status) {
467
		$status = (int)$status;
468
		if ($status !== FederatedLink::STATUS_LINK_UP
469
			&& $status !== FederatedLink::STATUS_LINK_REMOVE
470
		) {
471
			throw new FederatedCircleStatusUpdateException(
472
				$this->l10n->t('Cannot proceed with this status update')
473
			);
474
		}
475
	}
476
477
478
	/**
479
	 * checkUpdateLinkFromRemoteLinkUp()
480
	 *
481
	 * in case of a request of status update from remote for a link up, we check the current
482
	 * status of the link locally.
483
	 *
484
	 * @param Circle $circle
485
	 * @param FederatedLink $link
486
	 * @param int $status
487
	 *
488
	 * @throws FederatedCircleStatusUpdateException
489
	 */
490
	private function checkUpdateLinkFromRemoteLinkUp(Circle $circle, FederatedLink $link, $status) {
491
		if ((int)$status !== FederatedLink::STATUS_LINK_UP) {
492
			return;
493
		}
494
495
		if ($link->getStatus() !== FederatedLink::STATUS_REQUEST_SENT) {
496
			throw new FederatedCircleStatusUpdateException(
497
				$this->l10n->t('Cannot proceed with this status update')
498
			);
499
		}
500
501
		$this->eventsService->onLinkRequestAccepted($circle, $link);
502
		$this->eventsService->onLinkUp($circle, $link);
503
		$link->setStatus($status);
504
	}
505
506
507
	/**
508
	 * checkUpdateLinkFromRemoteLinkRemove();
509
	 *
510
	 * in case of a request of status update from remote for a link down, we check the current
511
	 * status of the link locally
512
	 *
513
	 * @param Circle $circle
514
	 * @param FederatedLink $link
515
	 * @param int $status
516
	 *
517
	 * @throws FederatedCircleStatusUpdateException
518
	 */
519
	private function checkUpdateLinkFromRemoteLinkRemove(Circle $circle, FederatedLink $link, $status) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 100 characters; contains 101 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
520
521
		if ((int)$status !== FederatedLink::STATUS_LINK_REMOVE) {
522
			return;
523
		}
524
525
		$curStatus = $link->getStatus();
526
		$this->checkUpdateLinkFromRemoteLinkRequestSent($circle, $link);
527
		$this->checkUpdateLinkFromRemoteLinkRequested($circle, $link);
528
		$this->checkUpdateLinkFromRemoteLinkDown($circle, $link);
529
530
		if ($curStatus !== $link->getStatus()) {
531
			return;
532
		}
533
534
		throw new FederatedCircleStatusUpdateException(
535
			$this->l10n->t('Cannot proceed with this status update')
536
		);
537
	}
538
539
540
	/**
541
	 * @param Circle $circle
542
	 * @param FederatedLink $link
543
	 */
544 View Code Duplication
	private function checkUpdateLinkFromRemoteLinkRequestSent(Circle $circle, FederatedLink &$link) {
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...
545
546
		if ($link->getStatus() !== FederatedLink::STATUS_REQUEST_SENT) {
547
			return;
548
		}
549
550
		$link->setStatus(FederatedLink::STATUS_REQUEST_DECLINED);
551
		$this->eventsService->onLinkRequestRejected($circle, $link);
552
	}
553
554
555
	/**
556
	 * @param Circle $circle
557
	 * @param FederatedLink $link
558
	 */
559 View Code Duplication
	private function checkUpdateLinkFromRemoteLinkRequested(Circle $circle, FederatedLink &$link) {
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...
560
561
		if ($link->getStatus() !== FederatedLink::STATUS_LINK_REQUESTED) {
562
			return;
563
		}
564
565
		$link->setStatus(FederatedLink::STATUS_LINK_REMOVE);
566
		$this->eventsService->onLinkRequestCanceled($circle, $link);
567
	}
568
569
570
	/**
571
	 * @param Circle $circle
572
	 * @param FederatedLink $link
573
	 */
574 View Code Duplication
	private function checkUpdateLinkFromRemoteLinkDown(Circle $circle, FederatedLink &$link) {
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...
575
576
		if ($link->getStatus() < FederatedLink::STATUS_LINK_DOWN) {
577
			return;
578
		}
579
580
		$link->setStatus(FederatedLink::STATUS_LINK_DOWN);
581
		$this->eventsService->onLinkDown($circle, $link);
582
	}
583
584
585
	/**
586
	 * updateLinkRemote()
587
	 *
588
	 * Send a request to the remote of the link to update its status.
589
	 *
590
	 * @param FederatedLink $link
591
	 *
592
	 * @return bool
593
	 * @throws Exception
594
	 */
595
	public function updateLinkRemote(FederatedLink &$link) {
596
		$args = [
597
			'apiVersion' => Circles::version(),
598
			'token'      => $link->getToken(true),
599
			'uniqueId'   => $link->getCircleId(true),
600
			'status'     => $link->getStatus()
601
		];
602
603
		$client = $this->clientService->newClient();
604
		try {
605
			$request = $client->post(
606
				$this->generateLinkRemoteURL($link->getAddress()), [
607
																	 'body'            => $args,
608
																	 'timeout'         => 10,
609
																	 'connect_timeout' => 10,
610
																 ]
611
			);
612
613
			$result = json_decode($request->getBody(), true);
614
			if ($result['status'] === -1) {
615
				throw new FederatedLinkUpdateException($result['reason']);
616
			}
617
618
			return true;
619
		} catch (Exception $e) {
620
			throw $e;
621
		}
622
	}
623
624
625
	/**
626
	 * Create a new link into database and assign the correct status.
627
	 *
628
	 * @param Circle $circle
629
	 * @param FederatedLink $link
630
	 *
631
	 * @throws Exception
632
	 */
633
	public function initiateLink(Circle $circle, FederatedLink &$link) {
634
635
		try {
636
			$this->checkLinkRequestValidity($circle, $link);
637
			$link->setCircleId($circle->getUniqueId());
638
639
			if ($circle->getSetting('allow_links_auto') === 'true') {
640
				$link->setStatus(FederatedLink::STATUS_LINK_UP);
641
				$this->eventsService->onLinkUp($circle, $link);
642
			} else {
643
				$link->setStatus(FederatedLink::STATUS_LINK_REQUESTED);
644
				$this->eventsService->onLinkRequestReceived($circle, $link);
645
			}
646
647
			$this->federatedLinksRequest->create($link);
648
		} catch (Exception $e) {
649
			throw $e;
650
		}
651
	}
652
653
654
	/**
655
	 * @param Circle $circle
656
	 * @param FederatedLink $link
657
	 *
658
	 * @throws FederatedLinkCreationException
659
	 */
660
	private function checkLinkRequestValidity($circle, $link) {
661
		if ($circle->getUniqueId(true) === $link->getUniqueId(true)) {
662
			throw new FederatedLinkCreationException('duplicate_unique_id');
663
		}
664
665
		try {
666
			$this->federatedLinksRequest->getLinkFromCircle(
667
				$circle->getUniqueId(), $link->getUniqueId(true)
668
			);
669
			throw new FederatedLinkCreationException('duplicate_link');
670
		} catch (FederatedLinkDoesNotExistException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
671
		}
672
673
		if ($circle->getSetting('allow_links') !== 'true') {
674
			throw new FederatedLinkCreationException('circle_links_disable');
675
		}
676
	}
677
678
679
}