Completed
Pull Request — master (#551)
by Maxence
02:42
created

RemoteController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.7
c 0
b 0
f 0
cc 1
nc 1
nop 9

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 2020
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\Controller;
33
34
use daita\MySmallPhpTools\Exceptions\InvalidItemException;
35
use daita\MySmallPhpTools\Exceptions\InvalidOriginException;
36
use daita\MySmallPhpTools\Exceptions\ItemNotFoundException;
37
use daita\MySmallPhpTools\Exceptions\MalformedArrayException;
38
use daita\MySmallPhpTools\Exceptions\SignatoryException;
39
use daita\MySmallPhpTools\Exceptions\SignatureException;
40
use daita\MySmallPhpTools\Exceptions\UnknownTypeException;
41
use daita\MySmallPhpTools\Model\Nextcloud\nc21\NC21SignedRequest;
42
use daita\MySmallPhpTools\Model\SimpleDataStore;
43
use daita\MySmallPhpTools\Traits\Nextcloud\nc21\TNC21Controller;
44
use Exception;
45
use OCA\Circles\Db\CircleRequest;
46
use OCA\Circles\Exceptions\CircleNotFoundException;
47
use OCA\Circles\Exceptions\FederatedEventDSyncException;
48
use OCA\Circles\Exceptions\FederatedItemException;
49
use OCA\Circles\Model\Federated\FederatedEvent;
50
use OCA\Circles\Model\Federated\RemoteInstance;
51
use OCA\Circles\Model\FederatedUser;
52
use OCA\Circles\Model\Member;
53
use OCA\Circles\Service\CircleService;
54
use OCA\Circles\Service\ConfigService;
55
use OCA\Circles\Service\FederatedUserService;
56
use OCA\Circles\Service\MemberService;
57
use OCA\Circles\Service\RemoteDownstreamService;
58
use OCA\Circles\Service\RemoteStreamService;
59
use OCP\AppFramework\Controller;
60
use OCP\AppFramework\Http;
61
use OCP\AppFramework\Http\DataResponse;
62
use OCP\IRequest;
63
64
65
/**
66
 * Class RemoteController
67
 *
68
 * @package OCA\Circles\Controller
69
 */
70
class RemoteController extends Controller {
71
72
73
	use TNC21Controller;
74
75
76
	/** @var CircleRequest */
77
	private $circleRequest;
78
79
	/** @var RemoteStreamService */
80
	private $remoteStreamService;
81
82
	/** @var RemoteDownstreamService */
83
	private $remoteDownstreamService;
84
85
	/** @var FederatedUserService */
86
	private $federatedUserService;
87
88
	/** @var CircleService */
89
	private $circleService;
90
91
	/** @var MemberService */
92
	private $memberService;
93
94
	/** @var ConfigService */
95
	private $configService;
96
97
98
	/**
99
	 * RemoteController constructor.
100
	 *
101
	 * @param string $appName
102
	 * @param IRequest $request
103
	 * @param CircleRequest $circleRequest
104
	 * @param RemoteStreamService $remoteStreamService
105
	 * @param RemoteDownstreamService $remoteDownstreamService
106
	 * @param FederatedUserService $federatedUserService
107
	 * @param CircleService $circleService
108
	 * @param MemberService $memberService
109
	 * @param ConfigService $configService
110
	 */
111
	public function __construct(
112
		string $appName, IRequest $request, CircleRequest $circleRequest,
113
		RemoteStreamService $remoteStreamService,
114
		RemoteDownstreamService $remoteDownstreamService, FederatedUserService $federatedUserService,
115
		CircleService $circleService, MemberService $memberService, ConfigService $configService
116
	) {
117
		parent::__construct($appName, $request);
118
		$this->circleRequest = $circleRequest;
119
		$this->remoteStreamService = $remoteStreamService;
120
		$this->remoteDownstreamService = $remoteDownstreamService;
121
		$this->federatedUserService = $federatedUserService;
122
		$this->circleService = $circleService;
123
		$this->memberService = $memberService;
124
		$this->configService = $configService;
125
126
		$this->setup('app', 'circles');
127
	}
128
129
130
	/**
131
	 * @PublicPage
132
	 * @NoCSRFRequired
133
	 *
134
	 * @return DataResponse
135
	 */
136
	public function event(): DataResponse {
137
		try {
138
			$event = $this->extractEventFromRequest();
139
		} catch (Exception $e) {
140
			return $this->fail($e, [], Http::STATUS_BAD_REQUEST);
141
		}
142
143
		try {
144
			$this->remoteDownstreamService->requestedEvent($event);
145
		} catch (FederatedItemException $e) {
146
			$this->e($e, ['event' => $event]);
147
			$event->setReadingOutcome($e->getMessage(), $e->getParams(), true);
148
		} catch (FederatedEventDSyncException $e) {
149
			return $this->fail($e, [], Http::STATUS_CONFLICT);
150
		} catch (Exception $e) {
151
			$this->e($e);
152
153
			return $this->fail($e, [], Http::STATUS_BAD_REQUEST);
154
		}
155
156
		return $this->successObj($event->getOutcome());
157
	}
158
159
160
	/**
161
	 * @PublicPage
162
	 * @NoCSRFRequired
163
	 *
164
	 * @return DataResponse
165
	 */
166
	public function incoming(): DataResponse {
167
		try {
168
			$event = $this->extractEventFromRequest();
169
170
			$result = $this->remoteDownstreamService->incomingEvent($event);
171
172
			return $this->success($result);
173
		} catch (Exception $e) {
174
			return $this->fail($e);
175
		}
176
	}
177
178
179
	/**
180
	 * @PublicPage
181
	 * @NoCSRFRequired
182
	 *
183
	 * @return DataResponse
184
	 * @throws InvalidOriginException
185
	 * @throws MalformedArrayException
186
	 * @throws SignatoryException
187
	 * @throws SignatureException
188
	 */
189
	public function test(): DataResponse {
190
		$test = $this->remoteStreamService->incomingSignedRequest($this->configService->getLocalInstance());
191
192
		return $this->successObj($test);
193
	}
194
195
196
	/**
197
	 * @PublicPage
198
	 * @NoCSRFRequired
199
	 *
200
	 * @return DataResponse
201
	 */
202
	public function circles(): DataResponse {
203
		try {
204
			$data = $this->extractDataFromFromRequest();
205
206
			/** @var Member $filter */
207
			$filter = $data->gObj('filter');
208
			$circles = $this->circleService->getCircles($filter);
209
210
			return $this->success($circles, false);
211
		} catch (Exception $e) {
212
			return $this->fail($e);
213
		}
214
	}
215
216
217
	/**
218
	 * @PublicPage
219
	 * @NoCSRFRequired
220
	 *
221
	 * @param string $circleId
222
	 *
223
	 * @return DataResponse
224
	 */
225
	public function circle(string $circleId): DataResponse {
226
		try {
227
			$this->extractDataFromFromRequest();
228
			$circle = $this->circleService->getCircle($circleId);
229
230
			return $this->successObj($circle);
231
		} catch (CircleNotFoundException $e) {
232
			return $this->success([], false);
233
		} catch (Exception $e) {
234
			return $this->fail($e);
235
		}
236
	}
237
238
239
	/**
240
	 * @PublicPage
241
	 * @NoCSRFRequired
242
	 *
243
	 * @param string $circleId
244
	 *
245
	 * @return DataResponse
246
	 */
247
	public function members(string $circleId): DataResponse {
248
		try {
249
			$this->extractDataFromFromRequest();
250
			$members = $this->memberService->getMembers($circleId);
251
252
			return $this->success($members, false);
253
		} catch (Exception $e) {
254
			return $this->fail($e);
255
		}
256
	}
257
258
259
	/**
260
	 * @PublicPage
261
	 * @NoCSRFRequired
262
	 *
263
	 * @param string $type
264
	 * @param string $userId
265
	 *
266
	 * @return DataResponse
267
	 */
268
	public function member(string $type, string $userId): DataResponse {
269
		try {
270
			$signed =
271
				$this->remoteStreamService->incomingSignedRequest($this->configService->getLocalInstance());
272
			$remoteInstance = $this->confirmRemoteInstance($signed);
0 ignored issues
show
Unused Code introduced by
$remoteInstance is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
273
274
//			$this->federatedUserService->setRemoteInstance($remoteInstance);
275
//			$this->federatedUserService->bypassCurrentUserCondition(true);
276
277
			$federatedUser = $this->federatedUserService->createLocalFederatedUser($userId);
278
279
			return $this->successObj($federatedUser);
280
		} catch (Exception $e) {
281
			return $this->fail($e);
282
		}
283
	}
284
285
286
	/**
287
	 * @param NC21SignedRequest $signedRequest
288
	 *
289
	 * @return RemoteInstance
290
	 * @throws SignatoryException
291
	 */
292
	private function confirmRemoteInstance(NC21SignedRequest $signedRequest): RemoteInstance {
293
		/** @var RemoteInstance $signatory */
294
		$signatory = $signedRequest->getSignatory();
295
296
		if (!$signatory instanceof RemoteInstance) {
297
			$this->debug('Signatory is not a known RemoteInstance', ['signedRequest' => $signedRequest]);
298
			throw new SignatoryException('Could not confirm identity');
299
		}
300
301
		if (!$this->configService->isLocalInstance($signedRequest->getOrigin())
302
			&& $signatory->getType() === RemoteInstance::TYPE_UNKNOWN) {
303
			$this->debug('Could not confirm identity', ['signedRequest' => $signedRequest]);
304
			throw new SignatoryException('Could not confirm identity');
305
		}
306
307
		return $signatory;
308
	}
309
310
311
	/**
312
	 * @return FederatedEvent
313
	 * @throws InvalidOriginException
314
	 * @throws MalformedArrayException
315
	 * @throws SignatoryException
316
	 * @throws SignatureException
317
	 * @throws InvalidItemException
318
	 */
319
	private function extractEventFromRequest(): FederatedEvent {
320
		$signed = $this->remoteStreamService->incomingSignedRequest($this->configService->getLocalInstance());
321
		$this->confirmRemoteInstance($signed);
322
323
		$event = new FederatedEvent();
324
		$event->import(json_decode($signed->getBody(), true));
325
		$event->setIncomingOrigin($signed->getOrigin());
326
327
		return $event;
328
	}
329
330
331
	/**
332
	 * @throws CircleNotFoundException
333
	 * @throws InvalidOriginException
334
	 * @throws MalformedArrayException
335
	 * @throws SignatoryException
336
	 * @throws SignatureException
337
	 * @throws UnknownTypeException
338
	 */
339
	private function extractDataFromFromRequest(): SimpleDataStore {
340
		$signed = $this->remoteStreamService->incomingSignedRequest($this->configService->getLocalInstance());
341
		$remoteInstance = $this->confirmRemoteInstance($signed);
342
343
		$data = new SimpleDataStore();
344
		$store = new SimpleDataStore(json_decode($signed->getBody(), true));
345
		try {
346
			/** @var FederatedUser $initiator */
347
			$initiator = $store->gObj('initiator', FederatedUser::class);
348
			if (is_null($initiator)) {
349
				throw new InvalidItemException();
350
			}
351
			$this->federatedUserService->setCurrentUser($initiator);
352
		} catch (InvalidItemException | ItemNotFoundException $e) {
353
			$this->federatedUserService->bypassCurrentUserCondition(true);
354
		}
355
356
		try {
357
			/** @var FederatedUser $initiator */
358
			$filter = $store->gObj('filter', Member::class);
359
			if (is_null($filter)) {
360
				throw new InvalidItemException();
361
			}
362
			$data->aObj('filter', $filter);
363
		} catch (InvalidItemException | ItemNotFoundException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
364
		}
365
366
		$this->federatedUserService->setRemoteInstance($remoteInstance);
367
368
		return $data;
369
	}
370
371
}
372
373