Completed
Push — master ( 27747c...bd517f )
by Maxence
05:20
created

ShareByCircleProvider::restore()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
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 OC\User\NoUserException;
38
use OCA\Circles\Api\v1\Circles;
39
use OCA\Circles\AppInfo\Application;
40
use OCA\Circles\Db\CircleProviderRequest;
41
use OCA\Circles\Db\CirclesRequest;
42
use OCA\Circles\Db\MembersRequest;
43
use OCA\Circles\Model\Circle;
44
use OCA\Circles\Service\CirclesService;
45
use OCA\Circles\Service\ConfigService;
46
use OCA\Circles\Service\MiscService;
47
use OCA\Circles\Service\TimezoneService;
48
use OCP\AppFramework\QueryException;
49
use OCP\DB\QueryBuilder\IQueryBuilder;
50
use OCP\Files\Folder;
51
use OCP\Files\IRootFolder;
52
use OCP\Files\Node;
53
use OCP\IDBConnection;
54
use OCP\IL10N;
55
use OCP\ILogger;
56
use OCP\IURLGenerator;
57
use OCP\IUserManager;
58
use OCP\Security\ISecureRandom;
59
use OCP\Share\Exceptions\ShareNotFound;
60
use OCP\Share\IShare;
61
use OCP\Share\IShareProvider;
62
63
64
class ShareByCircleProvider extends CircleProviderRequest implements IShareProvider {
65
66
	/** @var ILogger */
67
	private $logger;
68
69
	/** @var ISecureRandom */
70
	private $secureRandom;
71
72
	/** @var IUserManager */
73
	private $userManager;
74
75
	/** @var IRootFolder */
76
	private $rootFolder;
77
78
	/** @var IURLGenerator */
79
	private $urlGenerator;
80
81
	/** @var CirclesRequest */
82
	private $circlesRequest;
83
84
	/** @var MembersRequest */
85
	private $membersRequest;
86
87
88
	/**
89
	 * DefaultShareProvider constructor.
90
	 *
91
	 * @param IDBConnection $connection
92
	 * @param ISecureRandom $secureRandom
93
	 * @param IUserManager $userManager
94
	 * @param IRootFolder $rootFolder
95
	 * @param IL10N $l10n
96
	 * @param ILogger $logger
97
	 * @param IURLGenerator $urlGenerator
98
	 *
99
	 * @throws QueryException
100
	 */
101
	public function __construct(
102
		IDBConnection $connection, ISecureRandom $secureRandom, IUserManager $userManager,
103
		IRootFolder $rootFolder, IL10N $l10n, ILogger $logger, IURLGenerator $urlGenerator
104
	) {
105
		$app = new Application();
106
		$container = $app->getContainer();
107
		$configService = $container->query(ConfigService::class);
108
		$miscService = $container->query(MiscService::class);
109
		$timezoneService = $container->query(TimezoneService::class);
110
111
		parent::__construct($l10n, $connection, $configService, $timezoneService, $miscService);
112
113
		$this->secureRandom = $secureRandom;
114
		$this->userManager = $userManager;
115
		$this->rootFolder = $rootFolder;
116
		$this->logger = $logger;
117
		$this->urlGenerator = $urlGenerator;
118
		$this->circlesRequest = $container->query(CirclesRequest::class);
119
		$this->membersRequest = $container->query(MembersRequest::class);
120
	}
121
122
123
	/**
124
	 * Return the identifier of this provider.
125
	 *
126
	 * @return string
127
	 */
128
	public function identifier() {
129
		return 'ocCircleShare';
130
	}
131
132
133
	/**
134
	 * Create a share if it does not exist already.
135
	 *
136
	 * @param IShare $share
137
	 *
138
	 * @return IShare The share object
139
	 * @throws \Exception
140
	 */
141
	public function create(IShare $share) {
142
		try {
143
			$nodeId = $share->getNode()
144
							->getId();
145
146
			$qb = $this->findShareParentSql($nodeId, $share->getSharedWith());
147
			$exists = $qb->execute();
148
			$data = $exists->fetch();
149
			$exists->closeCursor();
150
151
			if ($data !== false) {
152
				throw $this->errorShareAlreadyExist($share);
153
			}
154
155
			$share->setToken(substr(bin2hex(openssl_random_pseudo_bytes(24)), 1, 15));
156
			$shareId = $this->createShare($share);
157
158
			$circle =
159
				$this->circlesRequest->getCircle($share->getSharedWith(), $share->getSharedby());
160
			$circle->getHigherViewer()
161
				   ->hasToBeMember();
162
163
			Circles::shareToCircle(
164
				$circle->getUniqueId(), 'files', '',
165
				['id' => $shareId, 'share' => $this->shareObjectToArray($share)],
166
				'\OCA\Circles\Circles\FileSharingBroadcaster'
167
			);
168
169
			return $this->getShareById($shareId);
170
		} catch (\Exception $e) {
171
			throw $e;
172
		}
173
	}
174
175
176
	/**
177
	 * Update a share
178
	 * permissions right, owner and initiator
179
	 *
180
	 * @param IShare $share
181
	 *
182
	 * @return IShare The share object
183
	 */
184
	public function update(IShare $share) {
185
186
		$qb = $this->getBaseUpdateSql();
187
		$this->limitToShare($qb, $share->getId());
188
		$qb->set('permissions', $qb->createNamedParameter($share->getPermissions()))
189
		   ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
190
		   ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()));
191
		$qb->execute();
192
193
		return $share;
194
	}
195
196
197
	/**
198
	 * Delete a share, and it's children
199
	 *
200
	 * @param IShare $share
201
	 */
202
	public function delete(IShare $share) {
203
204
		$qb = $this->getBaseDeleteSql();
205
		$this->limitToShareAndChildren($qb, $share->getId());
206
207
		$qb->execute();
208
	}
209
210
211
	/**
212
	 * Unshare a file from self as recipient.
213
	 * Because every circles share are group shares, we will set permissions to 0
214
	 *
215
	 * @param IShare $share
216
	 * @param string $userId
217
	 */
218 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...
219
		$childId = $this->getShareChildId($share, $userId);
220
221
		$qb = $this->getBaseUpdateSql();
222
		$qb->set('permissions', $qb->createNamedParameter(0));
223
		$this->limitToShare($qb, $childId);
224
225
		$qb->execute();
226
	}
227
228
229
	/**
230
	 * Move a share as a recipient.
231
	 *
232
	 * @param IShare $share
233
	 * @param string $userId
234
	 *
235
	 * @return IShare
236
	 *
237
	 */
238 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...
239
240
		$childId = $this->getShareChildId($share, $userId);
241
242
		$qb = $this->getBaseUpdateSql();
243
		$qb->set('file_target', $qb->createNamedParameter($share->getTarget()));
244
		$this->limitToShare($qb, $childId);
245
		$qb->execute();
246
247
		return $share;
248
	}
249
250
251
	/**
252
	 * return the child ID of a share
253
	 *
254
	 * @param IShare $share
255
	 * @param string $userId
256
	 *
257
	 * @return bool
258
	 */
259
	private function getShareChildId(IShare $share, $userId) {
260
		$qb = $this->getBaseSelectSql($share->getId());
261
		$this->limitToShareChildren($qb, $userId, $share->getId());
262
263
		$child = $qb->execute();
264
		$data = $child->fetch();
265
		$child->closeCursor();
266
267
		if ($data === false) {
268
			return $this->createShareChild($userId, $share);
269
		}
270
271
		return $data['id'];
272
	}
273
274
275
	/**
276
	 * Create a child and returns its ID
277
	 *
278
	 * @param IShare $share
279
	 *
280
	 * @return int
281
	 */
282
	private function createShare($share) {
283
		$qb = $this->getBaseInsertSql($share);
284
		$qb->execute();
285
		$id = $qb->getLastInsertId();
286
287
		return (int)$id;
288
	}
289
290
291
	/**
292
	 * Create a child and returns its ID
293
	 *
294
	 * @param string $userId
295
	 * @param IShare $share
296
	 *
297
	 * @return int
298
	 */
299
	private function createShareChild($userId, $share) {
300
		$qb = $this->getBaseInsertSql($share);
301
302
		$qb->setValue('parent', $qb->createNamedParameter($share->getId()));
303
		$qb->setValue('share_with', $qb->createNamedParameter($userId));
304
		$qb->execute();
305
		$id = $qb->getLastInsertId();
306
307
		return (int)$id;
308
	}
309
310
311
	/**
312
	 * Get all shares by the given user in a folder
313
	 *
314
	 * @param string $userId
315
	 * @param Folder $node
316
	 * @param bool $reshares Also get the shares where $user is the owner instead of just the
317
	 *     shares where $user is the initiator
318
	 *
319
	 * @return Share[]
320
	 */
321
	public function getSharesInFolder($userId, Folder $node, $reshares) {
322
		$qb = $this->getBaseSelectSql();
323
		$this->limitToShareOwner($qb, $userId, true);
324
		$cursor = $qb->execute();
325
326
		$shares = [];
327
		while ($data = $cursor->fetch()) {
328
			$shares[$data['file_source']][] = $this->createShareObject($data);
329
		}
330
		$cursor->closeCursor();
331
332
		return $shares;
333
	}
334
335
336
	/**
337
	 * Get all shares by the given user
338
	 *
339
	 * @param string $userId
340
	 * @param int $shareType
341
	 * @param Node|null $node
342
	 * @param bool $reShares
343
	 * @param int $limit The maximum number of shares to be returned, -1 for all shares
344
	 * @param int $offset
345
	 *
346
	 * @return Share[]
347
	 */
348
	public function getSharesBy($userId, $shareType, $node, $reShares, $limit, $offset) {
349
		$qb = $this->getBaseSelectSql();
350
		$this->limitToShareOwner($qb, $userId, $reShares);
351
352
		if ($node !== null) {
353
			$this->limitToFiles($qb, $node->getId());
354
		}
355
356
		$this->limitToPage($qb, $limit, $offset);
357
		$cursor = $qb->execute();
358
359
		$shares = [];
360
		while ($data = $cursor->fetch()) {
361
			$shares[] = $this->createShareObject($this->editShareEntry($data));
362
		}
363
		$cursor->closeCursor();
364
365
		return $shares;
366
	}
367
368
369
	/**
370
	 * returns a better formatted string to display more information about
371
	 * the circle to the Sharing UI
372
	 *
373
	 * @param $data
374
	 *
375
	 * @return array<string,string>
376
	 * @throws NoUserException
377
	 */
378
	private function editShareEntry($data) {
379
		$data['share_with'] =
380
			sprintf(
381
				'%s (%s, %s) [%s]', $data['circle_name'],
382
				Circle::TypeLongString($data['circle_type']),
383
				$this->miscService->getDisplayName($data['circle_owner']), $data['share_with']
384
			);
385
386
387
		return $data;
388
	}
389
390
391
	/**
392
	 * Get share by its id
393
	 *
394
	 * @param int $shareId
395
	 * @param string|null $recipientId
396
	 *
397
	 * @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...
398
	 * @throws ShareNotFound
399
	 */
400
	public function getShareById($shareId, $recipientId = null) {
401
		$qb = $this->getBaseSelectSql();
402
403
		$this->limitToShare($qb, $shareId);
404
405
		$cursor = $qb->execute();
406
		$data = $cursor->fetch();
407
		$cursor->closeCursor();
408
409
		if ($data === false) {
410
			throw new ShareNotFound();
411
		}
412
413
		return $this->createShareObject($data);
414
	}
415
416
417
	/**
418
	 * Get shares for a given path
419
	 *
420
	 * @param Node $path
421
	 *
422
	 * @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...
423
	 */
424 View Code Duplication
	public function getSharesByPath(Node $path) {
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...
425
		$qb = $this->getBaseSelectSql();
426
		$this->limitToFiles($qb, [$path->getId()]);
427
		$cursor = $qb->execute();
428
429
		$shares = [];
430
		while ($data = $cursor->fetch()) {
431
			$shares[] = $this->createShareObject($data);
432
		}
433
		$cursor->closeCursor();
434
435
		return $shares;
436
	}
437
438
439
	/**
440
	 * Get shared with the given user
441
	 *
442
	 * @param string $userId get shares where this user is the recipient
443
	 * @param int $shareType
444
	 * @param Node|null $node
445
	 * @param int $limit The max number of entries returned, -1 for all
446
	 * @param int $offset
447
	 *
448
	 * @return IShare[]
449
	 */
450
	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
451
452
		$shares = $this->getSharedWithCircleMembers($userId, $shareType, $node, $limit, $offset);
453
454
		return $shares;
455
	}
456
457
458
	/**
459
	 * @param string $userId
460
	 * @param $shareType
461
	 * @param Node $node
462
	 * @param int $limit
463
	 * @param int $offset
464
	 *
465
	 * @return IShare[]
466
	 */
467 View Code Duplication
	private function getSharedWithCircleMembers($userId, $shareType, $node, $limit, $offset) {
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...
468
469
		$qb = $this->getCompleteSelectSql();
470
		$this->linkToFileCache($qb, $userId);
471
		$this->limitToPage($qb, $limit, $offset);
472
473
		if ($node !== null) {
474
			$this->limitToFiles($qb, [$node->getId()]);
475
		}
476
477
		$this->linkToMember($qb, $userId, $this->configService->isLinkedGroupsAllowed());
478
479
		$cursor = $qb->execute();
480
481
		$shares = [];
482
		while ($data = $cursor->fetch()) {
483
			self::editShareFromParentEntry($data);
484
			if (self::isAccessibleResult($data)) {
485
				$shares[] = $this->createShareObject($data);
486
			}
487
		}
488
		$cursor->closeCursor();
489
490
		return $shares;
491
	}
492
493
494
	/**
495
	 * Get a share by token
496
	 *
497
	 * @param string $token
498
	 *
499
	 * @return IShare
500
	 * @throws ShareNotFound
501
	 * @deprecated - use local querybuilder lib instead
502
	 */
503
	public function getShareByToken($token) {
504
		$qb = $this->dbConnection->getQueryBuilder();
505
506
		$cursor = $qb->select('*')
507
					 ->from('share')
508
					 ->where(
509
						 $qb->expr()
510
							->eq(
511
								'share_type',
512
								$qb->createNamedParameter(\OCP\Share::SHARE_TYPE_CIRCLE)
513
							)
514
					 )
515
					 ->andWhere(
516
						 $qb->expr()
517
							->eq('token', $qb->createNamedParameter($token))
518
					 )
519
					 ->execute();
520
521
		$data = $cursor->fetch();
522
523
		if ($data === false) {
524
			throw new ShareNotFound('Share not found', $this->l10n->t('Could not find share'));
525
		}
526
527
		try {
528
			$share = $this->createShareObject($data);
529
		} 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...
530
			throw new ShareNotFound('Share not found', $this->l10n->t('Could not find share'));
531
		}
532
533
		return $share;
534
	}
535
536
537
	/**
538
	 * We don't return a thing about children.
539
	 * The call to this function is deprecated and should be removed in next release of NC.
540
	 * Also, we get the children in the delete() method.
541
	 *
542
	 * @param IShare $parent
543
	 *
544
	 * @return array
545
	 */
546
	public function getChildren(IShare $parent) {
547
		return [];
548
	}
549
550
551
	/**
552
	 * A user is deleted from the system
553
	 * So clean up the relevant shares.
554
	 *
555
	 * @param string $uid
556
	 * @param int $shareType
557
	 */
558
	public function userDeleted($uid, $shareType) {
559
		// TODO: Implement userDeleted() method.
560
	}
561
562
563
	/**
564
	 * A group is deleted from the system.
565
	 * We handle our own groups.
566
	 *
567
	 * @param string $gid
568
	 */
569
	public function groupDeleted($gid) {
570
		return;
571
	}
572
573
574
	/**
575
	 * A user is deleted from a group.
576
	 * We handle our own groups.
577
	 *
578
	 * @param string $uid
579
	 * @param string $gid
580
	 */
581
	public function userDeletedFromGroup($uid, $gid) {
582
		return;
583
	}
584
585
586
	/**
587
	 * Create a share object
588
	 *
589
	 * @param array $data
590
	 *
591
	 * @return IShare
592
	 */
593
	private function createShareObject($data) {
594
595
		$share = new Share($this->rootFolder, $this->userManager);
596
		$share->setId((int)$data['id'])
597
			  ->setPermissions((int)$data['permissions'])
598
			  ->setNodeType($data['item_type']);
599
600
		$share->setNodeId((int)$data['file_source'])
601
			  ->setTarget($data['file_target']);
602
603
		$this->assignShareObjectSharesProperties($share, $data);
604
		$this->assignShareObjectPropertiesFromParent($share, $data);
605
606
		$share->setProviderId($this->identifier());
607
608
		return $share;
609
	}
610
611
612
	/**
613
	 * @param IShare $share
614
	 * @param $data
615
	 */
616
	private function assignShareObjectPropertiesFromParent(IShare &$share, $data) {
617
		if (isset($data['f_permissions'])) {
618
			$entryData = $data;
619
			$entryData['permissions'] = $entryData['f_permissions'];
620
			$entryData['parent'] = $entryData['f_parent'];
621
			$share->setNodeCacheEntry(
622
				Cache::cacheEntryFromData(
623
					$entryData,
624
					\OC::$server->getMimeTypeLoader()
625
				)
626
			);
627
		}
628
	}
629
630
631
	/**
632
	 * @param IShare $share
633
	 * @param $data
634
	 */
635
	private function assignShareObjectSharesProperties(IShare &$share, $data) {
636
		$shareTime = new \DateTime();
637
		$shareTime->setTimestamp((int)$data['stime']);
638
639
		$share->setShareTime($shareTime);
640
		$share->setSharedWith($data['share_with'])
641
			  ->setSharedBy($data['uid_initiator'])
642
			  ->setShareOwner($data['uid_owner'])
643
			  ->setShareType((int)$data['share_type']);
644
645
		if (method_exists($share, 'setSharedWithDisplayName')) {
646
			$share->setSharedWithAvatar(CirclesService::getCircleIcon($data['circle_type']))
647
				  ->setSharedWithDisplayName(
648
					  sprintf(
649
						  '%s (%s, %s)', $data['circle_name'],
650
						  Circle::TypeLongString($data['circle_type']),
651
						  $this->miscService->getDisplayName($data['circle_owner'])
652
					  )
653
				  );
654
		}
655
	}
656
657
658
	/**
659
	 * @param IShare $share
660
	 *
661
	 * @return \Exception
662
	 */
663
	private function errorShareAlreadyExist($share) {
664
		$share_src = $share->getNode()
665
						   ->getName();
666
667
		$message = 'Sharing %s failed, this item is already shared with this circle';
668
		$message_t = $this->l10n->t($message, array($share_src));
669
		$this->logger->debug(
670
			sprintf($message, $share_src, $share->getSharedWith()), ['app' => 'circles']
671
		);
672
673
		return new \Exception($message_t);
674
	}
675
676
677
	/**
678
	 * Get the access list to the array of provided nodes.
679
	 *
680
	 * @see IManager::getAccessList() for sample docs
681
	 *
682
	 * @param Node[] $nodes The list of nodes to get access for
683
	 * @param bool $currentAccess If current access is required (like for removed shares that might
684
	 *     get revived later)
685
	 *
686
	 * @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...
687
	 * @since 12
688
	 */
689
	public function getAccessList($nodes, $currentAccess) {
690
		$ids = [];
691
		foreach ($nodes as $node) {
692
			$ids[] = $node->getId();
693
		}
694
695
		$qb = $this->getAccessListBaseSelectSql();
696
		$this->limitToFiles($qb, $ids);
697
698
		$users = $this->parseAccessListResult($qb);
699
700
		if ($currentAccess === false) {
701
			$users = array_keys($users);
702
		}
703
704
		return ['users' => $users];
705
	}
706
707
708
	/**
709
	 * Restore a share for a given recipient. The implementation could be provider independant.
710
	 *
711
	 * @param IShare $share
712
	 * @param string $recipient
713
	 *
714
	 * @return IShare The restored share object
715
	 *
716
	 * @since 14.0.0
717
	 */
718
	public function restore(IShare $share, string $recipient): Ishare {
719
		return $share;
720
	}
721
722
723
	/**
724
	 * return array regarding getAccessList format.
725
	 * ie. \OC\Share20\Manager::getAccessList()
726
	 *
727
	 * @param IQueryBuilder $qb
728
	 *
729
	 * @return array
730
	 */
731
	private function parseAccessListResult(IQueryBuilder $qb) {
732
733
		$cursor = $qb->execute();
734
		$users = [];
735
736
		while ($row = $cursor->fetch()) {
737
			$userId = $row['user_id'];
738
739
			if (!key_exists($userId, $users)) {
740
				$users[$userId] = [
741
					'node_id'   => $row['file_source'],
742
					'node_path' => $row['file_target']
743
				];
744
			}
745
		}
746
		$cursor->closeCursor();
747
748
		return $users;
749
	}
750
751
752
	/**
753
	 * @param IShare $share
754
	 *
755
	 * @return array
756
	 */
757
	private function shareObjectToArray(IShare $share) {
758
		return [
759
			'sharedWith'  => $share->getSharedWith(),
760
			'sharedBy'    => $share->getSharedBy(),
761
			'nodeId'      => $share->getNodeId(),
762
			'shareOwner'  => $share->getShareOwner(),
763
			'permissions' => $share->getPermissions(),
764
			'token'       => $share->getToken(),
765
			'password'    => $share->getPassword()
766
		];
767
	}
768
}
769