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

MembersList   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 310
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
wmc 34
lcom 1
cbo 11
dl 0
loc 310
rs 9.68
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A configure() 0 10 1
B execute() 0 66 6
C getMembers() 0 70 11
C displayLeaf() 0 55 15
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
			$members = $this->remoteService->getMembersFromInstance($circleId, $instance, $data);
269
		} else {
270
			$this->federatedUserService->commandLineInitiator($initiator, $circleId, true);
271
			$members = $this->memberService->getMembers($circleId);
272
		}
273
274
		if (!is_null($tree)) {
275
			foreach ($members as $member) {
276
				if ($member->getUserType() === Member::TYPE_CIRCLE) {
277
					if ($instance !== '' && !$this->configService->isLocalInstance($instance)) {
278
						$data = [];
279
						if ($initiator) {
280
							$data['initiator'] = $this->federatedUserService->getFederatedUser($initiator);
281
						}
282
283
						$circle = $this->remoteService->getCircleFromInstance(
284
							$member->getSingleId(), $instance, $data
285
						);
286
					} else {
287
						$this->federatedUserService->commandLineInitiator(
288
							$initiator, $member->getSingleId(), true
289
						);
290
						$circle = $this->circleService->getCircle($member->getSingleId());
291
					}
292
					$node = new NC21TreeNode(
293
						$tree, new SimpleDataStore(
294
								 [
295
									 'circle'  => $circle,
296
									 'member'  => $member,
297
									 'cycling' => in_array($member->getSingleId(), $knownIds)
298
								 ]
299
							 )
300
					);
301
302
					$this->getMembers(
303
						$member->getSingleId(), $member->getInstance(), $initiator, $node, $knownIds
304
					);
305
				} else {
306
					new NC21TreeNode(
307
						$tree, new SimpleDataStore(
308
								 [
309
									 'member'  => $member,
310
									 'cycling' => in_array($member->getSingleId(), $knownIds)
311
								 ]
312
							 )
313
					);
314
				}
315
			}
316
		}
317
318
		return $members;
319
	}
320
321
322
	/**
323
	 * @param SimpleDataStore $data
324
	 * @param int $lineNumber
325
	 *
326
	 * @return string
327
	 * @throws OwnerNotFoundException
328
	 */
329
	public function displayLeaf(SimpleDataStore $data, int $lineNumber): string {
330
		if ($lineNumber === 3) {
331
			return ($data->gBool('cycling')) ? '<comment>(loop detected)</comment>' : '';
332
		}
333
334
		try {
335
			$line = '';
336
			$circle = null;
337
			if ($data->hasKey('circle')) {
338
				/** @var Circle $circle */
339
				$circle = $data->gObj('circle', Circle::class);
340
			}
341
342
			if ($data->hasKey('member')) {
343
				/** @var Member $member */
344
				$member = $data->gObj('member', Member::class);
345
346
				if ($lineNumber === 1) {
347
					$line .= '<info>' . $member->getUserId() . '</info>';
348
					if (!$this->configService->isLocalInstance($member->getInstance())) {
349
						$line .= '@' . $member->getInstance();
350
					}
351
					$line .= ' (' . Member::$DEF_LEVEL[$member->getLevel()] . ')';
352
353
					if (!is_null($circle)) {
354
						$line .= ' <info>Name</info>: ' . $circle->getName();
355
					}
356
				}
357
358
				if ($lineNumber === 2 && !is_null($circle)) {
359
					$owner = $circle->getOwner();
360
					$line .= '<info>Owner</info>: ' . $owner->getUserId() . '@' . $owner->getInstance();
361
					$type =
362
						implode(
363
							", ", $this->modelManager->getCircleTypes($circle, ModelManager::TYPES_LONG)
364
						);
365
					$line .= ($type === '') ? '' : ' <info>Config</info>: ' . $type;
366
				}
367
368
			} else {
369
				if ($lineNumber === 1 && !is_null($circle)) {
370
					$line .= '<info>' . $circle->getId() . '</info>';
371
					if (!$this->configService->isLocalInstance($circle->getInstance())) {
372
						$line .= '@' . $circle->getInstance();
373
					}
374
				}
375
			}
376
377
			return $line;
378
379
		} 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...
380
		}
381
382
		return '';
383
	}
384
385
}
386
387