Completed
Push — master ( e1cf98...726ac6 )
by Maxence
02:32
created

ShareByCircleProvider   D

Complexity

Total Complexity 51

Size/Duplication

Total Lines 693
Duplicated Lines 4.91 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 5
Bugs 1 Features 0
Metric Value
wmc 51
c 5
b 1
f 0
lcom 1
cbo 9
dl 34
loc 693
rs 4.6908

29 Methods

Rating   Name   Duplication   Size   Complexity  
A identifier() 0 3 1
A getSharedWith() 0 6 1
A __construct() 0 19 1
A update() 0 11 1
A delete() 0 7 1
A deleteFromSelf() 9 9 1
A move() 11 11 1
A getShareChildId() 0 14 2
A createShare() 0 7 1
A createShareChild() 0 10 1
A getSharesInFolder() 0 13 2
A getSharesBy() 0 19 3
A editShareEntry() 0 9 1
B create() 0 33 3
A getShareById() 0 15 2
A getSharesByPath() 0 13 2
C getSharedWithCircleMembers() 14 34 7
B getShareByToken() 0 32 3
A getChildren() 0 3 1
A userDeleted() 0 3 1
A groupDeleted() 0 3 1
A userDeletedFromGroup() 0 3 1
A createShareObject() 0 17 1
A assignShareObjectPropertiesFromParent() 0 13 2
A assignShareObjectSharesProperties() 0 21 2
A errorShareAlreadyExist() 0 12 1
A getAccessList() 0 17 3
A parseAccessListResult() 0 19 3
A shareObjectToArray() 0 11 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ShareByCircleProvider often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ShareByCircleProvider, and based on these observations, apply Extract Interface, too.

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
 * @author Vinicius Cubas Brand <[email protected]>
10
 * @author Daniel Tygel <[email protected]>
11
 *
12
 * @copyright 2017
13
 * @license GNU AGPL version 3 or any later version
14
 *
15
 * This program is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License as
17
 * published by the Free Software Foundation, either version 3 of the
18
 * License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
 *
28
 */
29
30
31
namespace OCA\Circles;
32
33
34
use OC\Files\Cache\Cache;
35
use OC\Share20\Exception\InvalidShare;
36
use OC\Share20\Share;
37
use OCA\Circles\Api\v1\Circles;
38
use OCA\Circles\AppInfo\Application;
39
use OCA\Circles\Db\CircleProviderRequest;
40
use OCA\Circles\Db\CirclesRequest;
41
use OCA\Circles\Db\MembersRequest;
42
use OCA\Circles\Model\Circle;
43
use OCA\Circles\Model\Member;
44
use OCA\Circles\Service\CirclesService;
45
use OCA\Circles\Service\ConfigService;
46
use OCA\Circles\Service\MiscService;
47
use OCP\DB\QueryBuilder\IQueryBuilder;
48
use OCP\Files\Folder;
49
use OCP\Files\IRootFolder;
50
use OCP\Files\Node;
51
use OCP\IDBConnection;
52
use OCP\IL10N;
53
use OCP\ILogger;
54
use OCP\IURLGenerator;
55
use OCP\IUserManager;
56
use OCP\Security\ISecureRandom;
57
use OCP\Share\Exceptions\ShareNotFound;
58
use OCP\Share\IShare;
59
use OCP\Share\IShareProvider;
60
61
62
class ShareByCircleProvider extends CircleProviderRequest implements IShareProvider {
63
64
	/** @var ILogger */
65
	private $logger;
66
67
	/** @var ISecureRandom */
68
	private $secureRandom;
69
70
	/** @var IUserManager */
71
	private $userManager;
72
73
	/** @var IRootFolder */
74
	private $rootFolder;
75
76
	/** @var IURLGenerator */
77
	private $urlGenerator;
78
79
	/** @var CirclesRequest */
80
	private $circlesRequest;
81
82
	/** @var MembersRequest */
83
	private $membersRequest;
84
85
86
	/**
87
	 * DefaultShareProvider constructor.
88
	 *
89
	 * @param IDBConnection $connection
90
	 * @param ISecureRandom $secureRandom
91
	 * @param IUserManager $userManager
92
	 * @param IRootFolder $rootFolder
93
	 * @param IL10N $l10n
94
	 * @param ILogger $logger
95
	 * @param IURLGenerator $urlGenerator
96
	 */
97
	public function __construct(
98
		IDBConnection $connection, ISecureRandom $secureRandom, IUserManager $userManager,
99
		IRootFolder $rootFolder, IL10N $l10n, ILogger $logger, IURLGenerator $urlGenerator
100
	) {
101
		$app = new Application();
102
		$container = $app->getContainer();
103
		$configService = $container->query(ConfigService::class);
104
		$miscService = $container->query(MiscService::class);
105
106
		parent::__construct($l10n, $connection, $configService, $miscService);
107
108
		$this->secureRandom = $secureRandom;
109
		$this->userManager = $userManager;
110
		$this->rootFolder = $rootFolder;
111
		$this->logger = $logger;
112
		$this->urlGenerator = $urlGenerator;
113
		$this->circlesRequest = $container->query(CirclesRequest::class);
114
		$this->membersRequest = $container->query(MembersRequest::class);
115
	}
116
117
118
	/**
119
	 * Return the identifier of this provider.
120
	 *
121
	 * @return string
122
	 */
123
	public function identifier() {
124
		return 'ocCircleShare';
125
	}
126
127
128
	/**
129
	 * Create a share if it does not exist already.
130
	 *
131
	 * @param IShare $share
132
	 *
133
	 * @return IShare The share object
134
	 * @throws \Exception
135
	 */
136
	public function create(IShare $share) {
137
		try {
138
			$nodeId = $share->getNode()
139
							->getId();
140
141
			$qb = $this->findShareParentSql($nodeId, $share->getSharedWith());
142
			$exists = $qb->execute();
143
			$data = $exists->fetch();
144
			$exists->closeCursor();
145
146
			if ($data !== false) {
147
				throw $this->errorShareAlreadyExist($share);
148
			}
149
150
			$share->setToken(substr(bin2hex(openssl_random_pseudo_bytes(24)), 1, 15));
151
			$shareId = $this->createShare($share);
152
153
			$circle =
154
				$this->circlesRequest->getCircle($share->getSharedWith(), $share->getSharedby());
155
			$circle->getHigherViewer()
156
				   ->hasToBeMember();
157
158
			Circles::shareToCircle(
159
				$circle->getUniqueId(), 'files', '',
160
				['id' => $shareId, 'share' => $this->shareObjectToArray($share)],
161
				'\OCA\Circles\Circles\FileSharingBroadcaster'
162
			);
163
164
			return $this->getShareById($shareId);
165
		} catch (\Exception $e) {
166
			throw $e;
167
		}
168
	}
169
170
171
	/**
172
	 * Update a share
173
	 * permissions right, owner and initiator
174
	 *
175
	 * @param IShare $share
176
	 *
177
	 * @return IShare The share object
178
	 */
179
	public function update(IShare $share) {
180
181
		$qb = $this->getBaseUpdateSql();
182
		$this->limitToShare($qb, $share->getId());
183
		$qb->set('permissions', $qb->createNamedParameter($share->getPermissions()))
184
		   ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
185
		   ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()));
186
		$qb->execute();
187
188
		return $share;
189
	}
190
191
192
	/**
193
	 * Delete a share, and it's children
194
	 *
195
	 * @param IShare $share
196
	 */
197
	public function delete(IShare $share) {
198
199
		$qb = $this->getBaseDeleteSql();
200
		$this->limitToShareAndChildren($qb, $share->getId());
201
202
		$qb->execute();
203
	}
204
205
206
	/**
207
	 * Unshare a file from self as recipient.
208
	 * Because every circles share are group shares, we will set permissions to 0
209
	 *
210
	 * @param IShare $share
211
	 * @param string $userId
212
	 */
213 View Code Duplication
	public function deleteFromSelf(IShare $share, $userId) {
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...
214
		$childId = $this->getShareChildId($share, $userId);
215
216
		$qb = $this->getBaseUpdateSql();
217
		$qb->set('permissions', $qb->createNamedParameter(0));
218
		$this->limitToShare($qb, $childId);
219
220
		$qb->execute();
221
	}
222
223
224
	/**
225
	 * Move a share as a recipient.
226
	 *
227
	 * @param IShare $share
228
	 * @param string $userId
229
	 *
230
	 * @return IShare
231
	 *
232
	 */
233 View Code Duplication
	public function move(IShare $share, $userId) {
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...
234
235
		$childId = $this->getShareChildId($share, $userId);
236
237
		$qb = $this->getBaseUpdateSql();
238
		$qb->set('file_target', $qb->createNamedParameter($share->getTarget()));
239
		$this->limitToShare($qb, $childId);
240
		$qb->execute();
241
242
		return $share;
243
	}
244
245
246
	/**
247
	 * return the child ID of a share
248
	 *
249
	 * @param IShare $share
250
	 * @param string $userId
251
	 *
252
	 * @return bool
253
	 */
254
	private function getShareChildId(IShare $share, $userId) {
255
		$qb = $this->getBaseSelectSql($share->getId());
256
		$this->limitToShareChildren($qb, $userId, $share->getId());
257
258
		$child = $qb->execute();
259
		$data = $child->fetch();
260
		$child->closeCursor();
261
262
		if ($data === false) {
263
			return $this->createShareChild($userId, $share);
264
		}
265
266
		return $data['id'];
267
	}
268
269
270
	/**
271
	 * Create a child and returns its ID
272
	 *
273
	 * @param IShare $share
274
	 *
275
	 * @return int
276
	 */
277
	private function createShare($share) {
278
		$qb = $this->getBaseInsertSql($share);
279
		$qb->execute();
280
		$id = $qb->getLastInsertId();
281
282
		return (int)$id;
283
	}
284
285
286
	/**
287
	 * Create a child and returns its ID
288
	 *
289
	 * @param string $userId
290
	 * @param IShare $share
291
	 *
292
	 * @return int
293
	 */
294
	private function createShareChild($userId, $share) {
295
		$qb = $this->getBaseInsertSql($share);
296
297
		$qb->setValue('parent', $qb->createNamedParameter($share->getId()));
298
		$qb->setValue('share_with', $qb->createNamedParameter($userId));
299
		$qb->execute();
300
		$id = $qb->getLastInsertId();
301
302
		return (int)$id;
303
	}
304
305
306
	/**
307
	 * Get all shares by the given user in a folder
308
	 *
309
	 * @param string $userId
310
	 * @param Folder $node
311
	 * @param bool $reshares Also get the shares where $user is the owner instead of just the
312
	 *     shares where $user is the initiator
313
	 *
314
	 * @return Share[]
315
	 */
316
	public function getSharesInFolder($userId, Folder $node, $reshares) {
317
		$qb = $this->getBaseSelectSql();
318
		$this->limitToShareOwner($qb, $userId, true);
319
		$cursor = $qb->execute();
320
321
		$shares = [];
322
		while ($data = $cursor->fetch()) {
323
			$shares[$data['file_source']][] = $this->createShareObject($data);
324
		}
325
		$cursor->closeCursor();
326
327
		return $shares;
328
	}
329
330
331
	/**
332
	 * Get all shares by the given user
333
	 *
334
	 * @param string $userId
335
	 * @param int $shareType
336
	 * @param Node|null $node
337
	 * @param bool $reShares
338
	 * @param int $limit The maximum number of shares to be returned, -1 for all shares
339
	 * @param int $offset
340
	 *
341
	 * @return Share[]
342
	 */
343
	public function getSharesBy($userId, $shareType, $node, $reShares, $limit, $offset) {
344
		$qb = $this->getBaseSelectSql();
345
		$this->limitToShareOwner($qb, $userId, $reShares);
346
347
		if ($node !== null) {
348
			$this->limitToFiles($qb, $node->getId());
349
		}
350
351
		$this->limitToPage($qb, $limit, $offset);
352
		$cursor = $qb->execute();
353
354
		$shares = [];
355
		while ($data = $cursor->fetch()) {
356
			$shares[] = $this->createShareObject($this->editShareEntry($data));
357
		}
358
		$cursor->closeCursor();
359
360
		return $shares;
361
	}
362
363
364
	/**
365
	 * returns a better formatted string to display more information about
366
	 * the circle to the Sharing UI
367
	 *
368
	 * @param $data
369
	 *
370
	 * @return array<string,string>
371
	 */
372
	private function editShareEntry($data) {
373
		$data['share_with'] =
374
			sprintf(
375
				'%s (%s, %s)', $data['circle_name'], Circle::TypeLongString($data['circle_type']),
376
				$this->miscService->getDisplayName($data['circle_owner'])
377
			);
378
379
		return $data;
380
	}
381
382
383
	/**
384
	 * Get share by its id
385
	 *
386
	 * @param int $shareId
387
	 * @param string|null $recipientId
388
	 *
389
	 * @return Share
0 ignored issues
show
Documentation introduced by
Should the return type not be IShare?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
390
	 * @throws ShareNotFound
391
	 */
392
	public function getShareById($shareId, $recipientId = null) {
393
		$qb = $this->getBaseSelectSql();
394
395
		$this->limitToShare($qb, $shareId);
396
397
		$cursor = $qb->execute();
398
		$data = $cursor->fetch();
399
		$cursor->closeCursor();
400
401
		if ($data === false) {
402
			throw new ShareNotFound();
403
		}
404
405
		return $this->createShareObject($data);
406
	}
407
408
409
	/**
410
	 * Get shares for a given path
411
	 *
412
	 * @param Node $path
413
	 *
414
	 * @return IShare[]|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
415
	 */
416
	public function getSharesByPath(Node $path) {
417
		$qb = $this->getBaseSelectSql();
418
		$this->limitToFiles($qb, [$path->getId()]);
419
		$cursor = $qb->execute();
420
421
		$shares = [];
422
		while ($data = $cursor->fetch()) {
423
			$shares[] = $this->createShareObject($data);
424
		}
425
		$cursor->closeCursor();
426
427
		return $shares;
428
	}
429
430
431
	/**
432
	 * Get shared with the given user
433
	 *
434
	 * @param string $userId get shares where this user is the recipient
435
	 * @param int $shareType
436
	 * @param Node|null $node
437
	 * @param int $limit The max number of entries returned, -1 for all
438
	 * @param int $offset
439
	 *
440
	 * @return IShare[]
441
	 */
442
	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
443
444
		$shares = $this->getSharedWithCircleMembers($userId, $shareType, $node, $limit, $offset);
445
446
		return $shares;
447
	}
448
449
450
	/**
451
	 * @param string $userId
452
	 * @param $shareType
453
	 * @param Node $node
454
	 * @param int $limit
455
	 * @param int $offset
456
	 *
457
	 * @return IShare[]
458
	 */
459
	private function getSharedWithCircleMembers($userId, $shareType, $node, $limit, $offset) {
460
461
		$qb = $this->getCompleteSelectSql();
462
		$this->linkToFileCache($qb, $userId);
463
		$this->limitToPage($qb, $limit, $offset);
464
465
		if ($node !== null) {
466
			$this->limitToFiles($qb, [$node->getId()]);
467
		}
468
469
		$this->linkToMember($qb, $userId, $this->configService->isLinkedGroupsAllowed());
470
471
		$this->leftJoinShareInitiator($qb);
472
		$cursor = $qb->execute();
473
474
		$shares = [];
475 View Code Duplication
		while ($data = $cursor->fetch()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
476
477
			if ($data['initiator_circle_level'] < Member::LEVEL_MEMBER
478
				&& ($data['initiator_group_level'] < Member::LEVEL_MEMBER
479
					|| !$this->configService->isLinkedGroupsAllowed())
480
			) {
481
				continue;
482
			}
483
484
			self::editShareFromParentEntry($data);
485
			if (self::isAccessibleResult($data)) {
486
				$shares[] = $this->createShareObject($data);
487
			}
488
		}
489
		$cursor->closeCursor();
490
491
		return $shares;
492
	}
493
494
495
	/**
496
	 * Get a share by token
497
	 *
498
	 * @param string $token
499
	 *
500
	 * @return IShare
501
	 * @throws ShareNotFound
502
	 * @deprecated - use local querybuilder lib instead
503
	 */
504
	public function getShareByToken($token) {
505
		$qb = $this->dbConnection->getQueryBuilder();
506
507
		$cursor = $qb->select('*')
508
					 ->from('share')
509
					 ->where(
510
						 $qb->expr()
511
							->eq(
512
								'share_type',
513
								$qb->createNamedParameter(\OCP\Share::SHARE_TYPE_CIRCLE)
514
							)
515
					 )
516
					 ->andWhere(
517
						 $qb->expr()
518
							->eq('token', $qb->createNamedParameter($token))
519
					 )
520
					 ->execute();
521
522
		$data = $cursor->fetch();
523
524
		if ($data === false) {
525
			throw new ShareNotFound('Share not found', $this->l10n->t('Could not find share'));
526
		}
527
528
		try {
529
			$share = $this->createShareObject($data);
530
		} catch (InvalidShare $e) {
0 ignored issues
show
Bug introduced by
The class OC\Share20\Exception\InvalidShare does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
531
			throw new ShareNotFound('Share not found', $this->l10n->t('Could not find share'));
532
		}
533
534
		return $share;
535
	}
536
537
538
	/**
539
	 * We don't return a thing about children.
540
	 * The call to this function is deprecated and should be removed in next release of NC.
541
	 * Also, we get the children in the delete() method.
542
	 *
543
	 * @param IShare $parent
544
	 *
545
	 * @return array
546
	 */
547
	public function getChildren(IShare $parent) {
548
		return [];
549
	}
550
551
552
	/**
553
	 * A user is deleted from the system
554
	 * So clean up the relevant shares.
555
	 *
556
	 * @param string $uid
557
	 * @param int $shareType
558
	 */
559
	public function userDeleted($uid, $shareType) {
560
		// TODO: Implement userDeleted() method.
561
	}
562
563
564
	/**
565
	 * A group is deleted from the system.
566
	 * We handle our own groups.
567
	 *
568
	 * @param string $gid
569
	 */
570
	public function groupDeleted($gid) {
571
		return;
572
	}
573
574
575
	/**
576
	 * A user is deleted from a group.
577
	 * We handle our own groups.
578
	 *
579
	 * @param string $uid
580
	 * @param string $gid
581
	 */
582
	public function userDeletedFromGroup($uid, $gid) {
583
		return;
584
	}
585
586
587
	/**
588
	 * Create a share object
589
	 *
590
	 * @param array $data
591
	 *
592
	 * @return IShare
593
	 */
594
	private function createShareObject($data) {
595
596
		$share = new Share($this->rootFolder, $this->userManager);
597
		$share->setId((int)$data['id'])
598
			  ->setPermissions((int)$data['permissions'])
599
			  ->setNodeType($data['item_type']);
600
601
		$share->setNodeId((int)$data['file_source'])
602
			  ->setTarget($data['file_target']);
603
604
		$this->assignShareObjectSharesProperties($share, $data);
605
		$this->assignShareObjectPropertiesFromParent($share, $data);
606
607
		$share->setProviderId($this->identifier());
608
609
		return $share;
610
	}
611
612
613
	/**
614
	 * @param IShare $share
615
	 * @param $data
616
	 */
617
	private function assignShareObjectPropertiesFromParent(IShare &$share, $data) {
618
		if (isset($data['f_permissions'])) {
619
			$entryData = $data;
620
			$entryData['permissions'] = $entryData['f_permissions'];
621
			$entryData['parent'] = $entryData['f_parent'];
622
			$share->setNodeCacheEntry(
623
				Cache::cacheEntryFromData(
624
					$entryData,
625
					\OC::$server->getMimeTypeLoader()
626
				)
627
			);
628
		}
629
	}
630
631
632
	/**
633
	 * @param IShare $share
634
	 * @param $data
635
	 */
636
	private function assignShareObjectSharesProperties(IShare &$share, $data) {
637
		$shareTime = new \DateTime();
638
		$shareTime->setTimestamp((int)$data['stime']);
639
640
		$share->setShareTime($shareTime);
641
		$share->setSharedWith($data['share_with'])
642
			  ->setSharedBy($data['uid_initiator'])
643
			  ->setShareOwner($data['uid_owner'])
644
			  ->setShareType((int)$data['share_type']);
645
646
		if (method_exists($share, 'setSharedWithDisplayName')) {
647
			$share->setSharedWithAvatar(CirclesService::getCircleIcon($data['circle_type']))
648
				  ->setSharedWithDisplayName(
649
					  sprintf(
650
						  '%s (%s, %s)', $data['circle_name'],
651
						  Circle::TypeLongString($data['circle_type']),
652
						  $this->miscService->getDisplayName($data['circle_owner'])
653
					  )
654
				  );
655
		}
656
	}
657
658
659
	/**
660
	 * @param IShare $share
661
	 *
662
	 * @return \Exception
663
	 */
664
	private function errorShareAlreadyExist($share) {
665
		$share_src = $share->getNode()
666
						   ->getName();
667
668
		$message = 'Sharing %s failed, this item is already shared with this circle';
669
		$message_t = $this->l10n->t($message, array($share_src));
670
		$this->logger->debug(
671
			sprintf($message, $share_src, $share->getSharedWith()), ['app' => 'circles']
672
		);
673
674
		return new \Exception($message_t);
675
	}
676
677
678
	/**
679
	 * Get the access list to the array of provided nodes.
680
	 *
681
	 * @see IManager::getAccessList() for sample docs
682
	 *
683
	 * @param Node[] $nodes The list of nodes to get access for
684
	 * @param bool $currentAccess If current access is required (like for removed shares that might
685
	 *     get revived later)
686
	 *
687
	 * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
688
	 * @since 12
689
	 */
690
	public function getAccessList($nodes, $currentAccess) {
691
		$ids = [];
692
		foreach ($nodes as $node) {
693
			$ids[] = $node->getId();
694
		}
695
696
		$qb = $this->getAccessListBaseSelectSql();
697
		$this->limitToFiles($qb, $ids);
698
699
		$users = $this->parseAccessListResult($qb);
700
701
		if ($currentAccess === false) {
702
			$users = array_keys($users);
703
		}
704
705
		return ['users' => $users];
706
	}
707
708
709
	/**
710
	 * return array regarding getAccessList format.
711
	 * ie. \OC\Share20\Manager::getAccessList()
712
	 *
713
	 * @param IQueryBuilder $qb
714
	 *
715
	 * @return array
716
	 */
717
	private function parseAccessListResult(IQueryBuilder $qb) {
718
719
		$cursor = $qb->execute();
720
		$users = [];
721
722
		while ($row = $cursor->fetch()) {
723
			$userId = $row['user_id'];
724
725
			if (!key_exists($userId, $users)) {
726
				$users[$userId] = [
727
					'node_id'   => $row['file_source'],
728
					'node_path' => $row['file_target']
729
				];
730
			}
731
		}
732
		$cursor->closeCursor();
733
734
		return $users;
735
	}
736
737
738
	/**
739
	 * @param IShare $share
740
	 *
741
	 * @return array
742
	 */
743
	private function shareObjectToArray(IShare $share) {
744
		return [
745
			'sharedWith'  => $share->getSharedWith(),
746
			'sharedBy'    => $share->getSharedBy(),
747
			'nodeId'      => $share->getNodeId(),
748
			'shareOwner'  => $share->getShareOwner(),
749
			'permissions' => $share->getPermissions(),
750
			'token'       => $share->getToken(),
751
			'password'    => $share->getPassword()
752
		];
753
	}
754
}
755