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

MembersList::execute()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 63

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 63
rs 8.185
c 0
b 0
f 0
cc 6
nc 8
nop 2

How to fix   Long Method   

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