Completed
Pull Request — master (#361)
by Joas
01:56
created

ShareByCircleProvider::getAllShares()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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