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

MembersList::getMembers()   C

Complexity

Conditions 12
Paths 9

Size

Total Lines 78

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 78
rs 6.0533
c 0
b 0
f 0
cc 12
nc 9
nop 5

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 2017
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\Command;
33
34
use daita\MySmallPhpTools\Exceptions\InvalidItemException;
35
use daita\MySmallPhpTools\Exceptions\ItemNotFoundException;
36
use daita\MySmallPhpTools\Exceptions\RequestNetworkException;
37
use daita\MySmallPhpTools\Exceptions\SignatoryException;
38
use daita\MySmallPhpTools\Exceptions\UnknownTypeException;
39
use daita\MySmallPhpTools\Model\Nextcloud\nc21\NC21TreeNode;
40
use daita\MySmallPhpTools\Model\SimpleDataStore;
41
use daita\MySmallPhpTools\Traits\Nextcloud\nc21\TNC21ConsoleTree;
42
use OC\Core\Command\Base;
43
use OCA\Circles\Exceptions\CircleNotFoundException;
44
use OCA\Circles\Exceptions\FederatedUserException;
45
use OCA\Circles\Exceptions\FederatedUserNotFoundException;
46
use OCA\Circles\Exceptions\InitiatorNotFoundException;
47
use OCA\Circles\Exceptions\InvalidIdException;
48
use OCA\Circles\Exceptions\MemberNotFoundException;
49
use OCA\Circles\Exceptions\OwnerNotFoundException;
50
use OCA\Circles\Exceptions\RemoteInstanceException;
51
use OCA\Circles\Exceptions\RemoteNotFoundException;
52
use OCA\Circles\Exceptions\RemoteResourceNotFoundException;
53
use OCA\Circles\Exceptions\UnknownRemoteException;
54
use OCA\Circles\Exceptions\UserTypeNotFoundException;
55
use OCA\Circles\Model\Circle;
56
use OCA\Circles\Model\Member;
57
use OCA\Circles\Model\ModelManager;
58
use OCA\Circles\Service\CircleService;
59
use OCA\Circles\Service\ConfigService;
60
use OCA\Circles\Service\FederatedUserService;
61
use OCA\Circles\Service\MemberService;
62
use OCA\Circles\Service\RemoteService;
63
use Symfony\Component\Console\Helper\Table;
64
use Symfony\Component\Console\Input\InputArgument;
65
use Symfony\Component\Console\Input\InputInterface;
66
use Symfony\Component\Console\Input\InputOption;
67
use Symfony\Component\Console\Output\ConsoleOutput;
68
use Symfony\Component\Console\Output\OutputInterface;
69
70
71
/**
72
 * Class MembersList
73
 *
74
 * @package OCA\Circles\Command
75
 */
76
class MembersList extends Base {
77
78
79
	use TNC21ConsoleTree;
80
81
82
	/** @var ModelManager */
83
	private $modelManager;
84
85
	/** @var FederatedUserService */
86
	private $federatedUserService;
87
88
	/** @var RemoteService */
89
	private $remoteService;
90
91
	/** @var CircleService */
92
	private $circleService;
93
94
	/** @var MemberService */
95
	private $memberService;
96
97
	/** @var ConfigService */
98
	private $configService;
99
100
101
	/**
102
	 * MembersList constructor.
103
	 *
104
	 * @param ModelManager $modelManager
105
	 * @param FederatedUserService $federatedUserService
106
	 * @param RemoteService $remoteService
107
	 * @param CircleService $circleService
108
	 * @param MemberService $memberService
109
	 * @param ConfigService $configService
110
	 */
111
	public function __construct(
112
		ModelManager $modelManager, FederatedUserService $federatedUserService, RemoteService $remoteService,
113
		CircleService $circleService, MemberService $memberService, ConfigService $configService
114
	) {
115
		parent::__construct();
116
		$this->modelManager = $modelManager;
117
		$this->federatedUserService = $federatedUserService;
118
		$this->remoteService = $remoteService;
119
		$this->circleService = $circleService;
120
		$this->memberService = $memberService;
121
		$this->configService = $configService;
122
	}
123
124
125
	protected function configure() {
126
		parent::configure();
127
		$this->setName('circles:members:list')
128
			 ->setDescription('listing Members from a Circle')
129
			 ->addArgument('circle_id', InputArgument::REQUIRED, 'ID of the circle')
130
			 ->addOption('instance', '', InputOption::VALUE_REQUIRED, 'Instance of the circle', '')
131
			 ->addOption('initiator', '', InputOption::VALUE_REQUIRED, 'set an initiator to the request', '')
132
			 ->addOption('tree', '', InputOption::VALUE_NONE, 'display members as a tree')
133
			 ->addOption('json', '', InputOption::VALUE_NONE, 'returns result as JSON');
134
	}
135
136
137
	/**
138
	 * @param InputInterface $input
139
	 * @param OutputInterface $output
140
	 *
141
	 * @return int
142
	 * @throws CircleNotFoundException
143
	 * @throws InitiatorNotFoundException
144
	 * @throws OwnerNotFoundException
145
	 * @throws RemoteInstanceException
146
	 * @throws RemoteNotFoundException
147
	 * @throws RemoteResourceNotFoundException
148
	 * @throws RequestNetworkException
149
	 * @throws SignatoryException
150
	 * @throws UnknownRemoteException
151
	 * @throws FederatedUserException
152
	 * @throws FederatedUserNotFoundException
153
	 * @throws InvalidIdException
154
	 * @throws UserTypeNotFoundException
155
	 * @throws InvalidItemException
156
	 * @throws MemberNotFoundException
157
	 */
158
	protected function execute(InputInterface $input, OutputInterface $output): int {
159
		$circleId = $input->getArgument('circle_id');
160
		$instance = $input->getOption('instance');
161
		$initiator = $input->getOption('initiator');
162
163
		$tree = null;
164
		if ($input->getOption('tree')) {
165
			$this->federatedUserService->commandLineInitiator($initiator, $circleId, true);
166
			$circle = $this->circleService->getCircle($circleId);
167
			$output->writeln('<info>Name</info>: ' . $circle->getName());
168
			$owner = $circle->getOwner();
169
			$output->writeln('<info>Owner</info>: ' . $owner->getUserId() . '@' . $owner->getInstance());
170
			$type =
171
				implode(
172
					", ", $this->modelManager->getCircleTypes($circle, ModelManager::TYPES_LONG)
173
				);
174
			$output->writeln('<info>Config</info>: ' . $type);
175
			$output->writeln(' ');
176
177
			$tree = new NC21TreeNode(null, new SimpleDataStore(['circle' => $circle]));
178
		}
179
180
		$members = $this->getMembers($circleId, $instance, $initiator, $tree);
181
182
		if (!is_null($tree)) {
183
			$this->drawTree(
184
				$tree, [$this, 'displayLeaf'],
185
				[
186
					'height'       => 3,
187
					'node-spacing' => 1,
188
					'item-spacing' => 0,
189
				]
190
			);
191
192
			return 0;
193
		}
194
195
		if ($input->getOption('json')) {
196
			echo json_encode($members, JSON_PRETTY_PRINT) . "\n";
197
198
			return 0;
199
		}
200
201
		$output = new ConsoleOutput();
202
		$output = $output->section();
203
204
		$table = new Table($output);
205
		$table->setHeaders(['ID', 'Single ID', 'Type', 'Username', 'Instance', 'Level']);
206
		$table->render();
207
208
		$local = $this->configService->getLocalInstance();
209
		foreach ($members as $member) {
210
			$table->appendRow(
211
				[
212
					$member->getId(),
213
					$member->getSingleId(),
214
					Member::$DEF_TYPE[$member->getUserType()],
215
					$member->getUserId(),
216
					($member->getInstance() === $local) ? '' : $member->getInstance(),
217
					Member::$DEF_LEVEL[$member->getLevel()]
218
				]
219
			);
220
		}
221
222
		return 0;
223
	}
224
225
226
	/**
227
	 * @param string $circleId
228
	 * @param string $instance
229
	 * @param string $initiator
230
	 * @param NC21TreeNode|null $tree
231
	 * @param array $knownIds
232
	 *
233
	 * @return array
234
	 * @throws CircleNotFoundException
235
	 * @throws FederatedUserException
236
	 * @throws FederatedUserNotFoundException
237
	 * @throws InitiatorNotFoundException
238
	 * @throws InvalidIdException
239
	 * @throws InvalidItemException
240
	 * @throws MemberNotFoundException
241
	 * @throws OwnerNotFoundException
242
	 * @throws RemoteInstanceException
243
	 * @throws RemoteNotFoundException
244
	 * @throws RemoteResourceNotFoundException
245
	 * @throws RequestNetworkException
246
	 * @throws SignatoryException
247
	 * @throws UnknownRemoteException
248
	 * @throws UserTypeNotFoundException
249
	 */
250
	private function getMembers(
251
		string $circleId,
252
		string $instance,
253
		string $initiator,
254
		?NC21TreeNode $tree,
255
		array $knownIds = []
256
	): array {
257
		if (in_array($circleId, $knownIds)) {
258
			return [];
259
		}
260
		$knownIds[] = $circleId;
261
262
		if ($instance !== '' && !$this->configService->isLocalInstance($instance)) {
263
			$data = [];
264
			if ($initiator) {
265
				$data['initiator'] = $this->federatedUserService->getFederatedUser($initiator);
266
			}
267
268
			try {
269
				$members = $this->remoteService->getMembersFromInstance($circleId, $instance, $data);
270
			} catch (RemoteInstanceException $e) {
271
				return [];
272
			}
273
		} else {
274
			$this->federatedUserService->commandLineInitiator($initiator, $circleId, true);
275
			$members = $this->memberService->getMembers($circleId);
276
		}
277
278
		if (!is_null($tree)) {
279
			foreach ($members as $member) {
280
				if ($member->getUserType() === Member::TYPE_CIRCLE) {
281
					if (!$this->configService->isLocalInstance($member->getInstance())) {
282
						$data = [];
283
						if ($initiator) {
284
							$data['initiator'] = $this->federatedUserService->getFederatedUser($initiator);
285
						}
286
287
						$circle = null;
288
						try {
289
							$circle = $this->remoteService->getCircleFromInstance(
290
								$member->getSingleId(), $member->getInstance(), $data
291
							);
292
						} catch (CircleNotFoundException | RemoteInstanceException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
293
						}
294
					} else {
295
						$this->federatedUserService->commandLineInitiator(
296
							$initiator, $member->getSingleId(), true
297
						);
298
						$circle = $this->circleService->getCircle($member->getSingleId());
299
					}
300
					$node = new NC21TreeNode(
301
						$tree, new SimpleDataStore(
302
								 [
303
									 'circle'  => $circle,
304
									 'member'  => $member,
305
									 'cycling' => in_array($member->getSingleId(), $knownIds),
306
								 ]
307
							 )
308
					);
309
310
					$this->getMembers(
311
						$member->getSingleId(), $member->getInstance(), $initiator, $node, $knownIds
312
					);
313
				} else {
314
					new NC21TreeNode(
315
						$tree, new SimpleDataStore(
316
								 [
317
									 'member'  => $member,
318
									 'cycling' => in_array($member->getSingleId(), $knownIds)
319
								 ]
320
							 )
321
					);
322
				}
323
			}
324
		}
325
326
		return $members;
327
	}
328
329
330
	/**
331
	 * @param SimpleDataStore $data
332
	 * @param int $lineNumber
333
	 *
334
	 * @return string
335
	 * @throws OwnerNotFoundException
336
	 */
337
	public function displayLeaf(SimpleDataStore $data, int $lineNumber): string {
338
		if ($lineNumber === 3) {
339
			return ($data->gBool('cycling')) ? '<comment>(loop detected)</comment>' : '';
340
		}
341
342
		try {
343
			$line = '';
344
			$circle = null;
345
			if ($data->hasKey('circle')) {
346
				/** @var Circle $circle */
347
				$circle = $data->gObj('circle', Circle::class);
348
			}
349
350
			if ($data->hasKey('member')) {
351
				/** @var Member $member */
352
				$member = $data->gObj('member', Member::class);
353
354
				if ($lineNumber === 1) {
355
					$line .= '<info>' . $member->getUserId() . '</info>';
356
					if (!$this->configService->isLocalInstance($member->getInstance())) {
357
						$line .= '@' . $member->getInstance();
358
					}
359
					$line .= ' (' . Member::$DEF_LEVEL[$member->getLevel()] . ')';
360
361
					if (!is_null($circle)) {
362
						$line .= ' <info>Name</info>: ' . $circle->getName();
363
					}
364
				}
365
366
				if ($lineNumber === 2) {
367
					if (is_null($circle)) {
368
						if ($member->getUserType() === Member::TYPE_CIRCLE) {
369
							$line .= '<comment>(out of bounds)</comment>';
370
						}
371
372
						return $line;
373
					}
374
					$owner = $circle->getOwner();
375
					$line .= '<info>Owner</info>: ' . $owner->getUserId() . '@' . $owner->getInstance();
376
					$type =
377
						implode(
378
							", ", $this->modelManager->getCircleTypes($circle, ModelManager::TYPES_LONG)
379
						);
380
					$line .= ($type === '') ? '' : ' <info>Config</info>: ' . $type;
381
				}
382
383
			} else {
384
				if ($lineNumber === 1 && !is_null($circle)) {
385
					$line .= '<info>' . $circle->getId() . '</info>';
386
					if (!$this->configService->isLocalInstance($circle->getInstance())) {
387
						$line .= '@' . $circle->getInstance();
388
					}
389
				}
390
			}
391
392
			return $line;
393
394
		} catch (InvalidItemException | ItemNotFoundException | UnknownTypeException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
395
		}
396
397
		return '';
398
	}
399
400
}
401
402