Completed
Pull Request — master (#331)
by Maxence
01:41
created

ShareByCircleProvider::getShareByPersonalToken()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 52
rs 8.425
c 0
b 0
f 0
cc 6
nc 7
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * 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;
35
use OC\Files\Cache\Cache;
36
use OC\Share20\Exception\InvalidShare;
37
use OC\Share20\Share;
38
use OC\User\NoUserException;
39
use OCA\Circles\Api\v1\Circles;
40
use OCA\Circles\AppInfo\Application;
41
use OCA\Circles\Db\CircleProviderRequest;
42
use OCA\Circles\Db\CirclesRequest;
43
use OCA\Circles\Db\MembersRequest;
44
use OCA\Circles\Db\TokensRequest;
45
use OCA\Circles\Model\Circle;
46
use OCA\Circles\Model\Member;
47
use OCA\Circles\Service\CirclesService;
48
use OCA\Circles\Service\ConfigService;
49
use OCA\Circles\Service\MembersService;
50
use OCA\Circles\Service\MiscService;
51
use OCA\Circles\Service\TimezoneService;
52
use OCP\AppFramework\QueryException;
53
use OCP\DB\QueryBuilder\IQueryBuilder;
54
use OCP\Files\Folder;
55
use OCP\Files\IRootFolder;
56
use OCP\Files\Node;
57
use OCP\Files\NotFoundException;
58
use OCP\IDBConnection;
59
use OCP\IL10N;
60
use OCP\ILogger;
61
use OCP\IURLGenerator;
62
use OCP\IUserManager;
63
use OCP\Security\ISecureRandom;
64
use OCP\Share\Exceptions\IllegalIDChangeException;
65
use OCP\Share\Exceptions\ShareNotFound;
66
use OCP\Share\IShare;
67
use OCP\Share\IShareProvider;
68
69
70
class ShareByCircleProvider extends CircleProviderRequest implements IShareProvider {
71
72
73
	/** @var ILogger */
74
	private $logger;
75
76
	/** @var ISecureRandom */
77
	private $secureRandom;
78
79
	/** @var IUserManager */
80
	private $userManager;
81
82
	/** @var IRootFolder */
83
	private $rootFolder;
84
85
	/** @var IURLGenerator */
86
	private $urlGenerator;
87
88
	/** @var MembersService */
89
	private $membersService;
90
91
	/** @var CirclesRequest */
92
	private $circlesRequest;
93
94
	/** @var MembersRequest */
95
	private $membersRequest;
96
97
	/** @var TokensRequest */
98
	private $tokensRequest;
99
100
	/**
101
	 * DefaultShareProvider constructor.
102
	 *
103
	 * @param IDBConnection $connection
104
	 * @param ISecureRandom $secureRandom
105
	 * @param IUserManager $userManager
106
	 * @param IRootFolder $rootFolder
107
	 * @param IL10N $l10n
108
	 * @param ILogger $logger
109
	 * @param IURLGenerator $urlGenerator
110
	 *
111
	 * @throws QueryException
112
	 */
113
	public function __construct(
114
		IDBConnection $connection, ISecureRandom $secureRandom, IUserManager $userManager,
115
		IRootFolder $rootFolder, IL10N $l10n, ILogger $logger, IURLGenerator $urlGenerator
116
	) {
117
		$app = new Application();
118
		$container = $app->getContainer();
119
		$configService = $container->query(ConfigService::class);
120
		$miscService = $container->query(MiscService::class);
121
		$timezoneService = $container->query(TimezoneService::class);
122
123
		parent::__construct($l10n, $connection, $configService, $timezoneService, $miscService);
124
125
		$this->secureRandom = $secureRandom;
126
		$this->userManager = $userManager;
127
		$this->rootFolder = $rootFolder;
128
		$this->logger = $logger;
129
		$this->urlGenerator = $urlGenerator;
130
		$this->membersService = $container->query(MembersService::class);
131
		$this->circlesRequest = $container->query(CirclesRequest::class);
132
		$this->membersRequest = $container->query(MembersRequest::class);
133
		$this->tokensRequest = $container->query(TokensRequest::class);
134
	}
135
136
137
	/**
138
	 * Return the identifier of this provider.
139
	 *
140
	 * @return string
141
	 */
142
	public function identifier() {
143
		return 'ocCircleShare';
144
	}
145
146
147
	/**
148
	 * Create a share if it does not exist already.
149
	 *
150
	 * @param IShare $share
151
	 *
152
	 * @return IShare The share object
153
	 * @throws \Exception
154
	 */
155
	public function create(IShare $share) {
156
		try {
157
			$nodeId = $share->getNode()
158
							->getId();
159
160
			$qb = $this->findShareParentSql($nodeId, $share->getSharedWith());
161
			$exists = $qb->execute();
162
			$data = $exists->fetch();
163
			$exists->closeCursor();
164
165
			if ($data !== false) {
166
				throw $this->errorShareAlreadyExist($share);
167
			}
168
169
			$share->setToken($this->miscService->uuid(15));
170
			if ($this->configService->enforcePasswordProtection()) {
171
				$share->setPassword($this->miscService->uuid(15));
172
			}
173
174
			$this->createShare($share);
175
176
			$circle =
177
				$this->circlesRequest->getCircle($share->getSharedWith(), $share->getSharedby());
178
			$circle->getHigherViewer()
179
				   ->hasToBeMember();
180
181
			Circles::shareToCircle(
182
				$circle->getUniqueId(), 'files', '',
183
				['id' => $share->getId(), 'share' => $this->shareObjectToArray($share)],
184
				'\OCA\Circles\Circles\FileSharingBroadcaster'
185
			);
186
187
			return $this->getShareById($share->getId());
188
		} catch (\Exception $e) {
189
			throw $e;
190
		}
191
	}
192
193
194
	/**
195
	 * Update a share
196
	 * permissions right, owner and initiator
197
	 *
198
	 * @param IShare $share
199
	 *
200
	 * @return IShare The share object
201
	 */
202
	public function update(IShare $share) {
203
204
		$qb = $this->getBaseUpdateSql();
205
		$this->limitToShare($qb, $share->getId());
206
		$qb->set('permissions', $qb->createNamedParameter($share->getPermissions()))
207
		   ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
208
		   ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()));
209
		$qb->execute();
210
211
		return $share;
212
	}
213
214
215
	/**
216
	 * Delete a share, and it's children
217
	 *
218
	 * @param IShare $share
219
	 */
220
	public function delete(IShare $share) {
221
		$qb = $this->getBaseDeleteSql();
222
		$this->limitToShareAndChildren($qb, $share->getId());
223
		$qb->execute();
224
225
		$this->tokensRequest->removeTokenByShareId($share->getId());
226
	}
227
228
229
	/**
230
	 * Unshare a file from self as recipient.
231
	 * Because every circles share are group shares, we will set permissions to 0
232
	 *
233
	 * @param IShare $share
234
	 * @param string $userId
235
	 */
236 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...
237
		$childId = $this->getShareChildId($share, $userId);
238
239
		$qb = $this->getBaseUpdateSql();
240
		$qb->set('permissions', $qb->createNamedParameter(0));
241
		$this->limitToShare($qb, $childId);
242
243
		$qb->execute();
244
	}
245
246
247
	/**
248
	 * Move a share as a recipient.
249
	 *
250
	 * @param IShare $share
251
	 * @param string $userId
252
	 *
253
	 * @return IShare
254
	 *
255
	 */
256 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...
257
258
		$childId = $this->getShareChildId($share, $userId);
259
260
		$qb = $this->getBaseUpdateSql();
261
		$qb->set('file_target', $qb->createNamedParameter($share->getTarget()));
262
		$this->limitToShare($qb, $childId);
263
		$qb->execute();
264
265
		return $share;
266
	}
267
268
269
	/**
270
	 * return the child ID of a share
271
	 *
272
	 * @param IShare $share
273
	 * @param string $userId
274
	 *
275
	 * @return bool
276
	 */
277
	private function getShareChildId(IShare $share, $userId) {
278
		$qb = $this->getBaseSelectSql($share->getId());
279
		$this->limitToShareChildren($qb, $userId, $share->getId());
280
281
		$child = $qb->execute();
282
		$data = $child->fetch();
283
		$child->closeCursor();
284
285
		if ($data === false) {
286
			return $this->createShareChild($userId, $share);
287
		}
288
289
		return $data['id'];
290
	}
291
292
293
	/**
294
	 * Create a child and returns its ID
295
	 *
296
	 * @param IShare $share
297
	 *
298
	 * @throws NotFoundException
299
	 */
300
	private function createShare($share) {
301
		$this->miscService->log(
302
			'Creating share (1/4) - type: ' . $share->getShareType() . ' - token: '
303
			. $share->getToken() . ' - type: ' . $share->getShareType() . ' - with: '
304
			. $share->getSharedWith() . ' - permissions: ' . $share->getPermissions(), 0
305
		);
306
307
		$qb = $this->getBaseInsertSql($share);
308
		$this->miscService->log('Share creation (2/4) : ' . json_encode($qb->getSQL()), 0);
309
310
		$result = $qb->execute();
311
		$this->miscService->log('Share creation result (3/4) : ' . json_encode($result), 0);
312
313
		$id = $qb->getLastInsertId();
314
		$this->miscService->log('Share created ID (4/4) : ' . $id, 0);
315
316
		try {
317
			$share->setId($id);
318
		} 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...
319
		}
320
	}
321
322
323
	/**
324
	 * Create a child and returns its ID
325
	 *
326
	 * @param string $userId
327
	 * @param IShare $share
328
	 *
329
	 * @return int
330
	 */
331
	private function createShareChild($userId, $share) {
332
		$qb = $this->getBaseInsertSql($share);
333
334
		$qb->setValue('parent', $qb->createNamedParameter($share->getId()));
335
		$qb->setValue('share_with', $qb->createNamedParameter($userId));
336
		$qb->execute();
337
		$id = $qb->getLastInsertId();
338
339
		return (int)$id;
340
	}
341
342
343
	/**
344
	 * Get all shares by the given user in a folder
345
	 *
346
	 * @param string $userId
347
	 * @param Folder $node
348
	 * @param bool $reshares Also get the shares where $user is the owner instead of just the
349
	 *     shares where $user is the initiator
350
	 *
351
	 * @return Share[]
352
	 */
353
	public function getSharesInFolder($userId, Folder $node, $reshares) {
354
		$qb = $this->getBaseSelectSql();
355
		$this->limitToShareOwner($qb, $userId, true);
356
		$cursor = $qb->execute();
357
358
		$shares = [];
359
		while ($data = $cursor->fetch()) {
360
			$shares[$data['file_source']][] = $this->createShareObject($data);
361
		}
362
		$cursor->closeCursor();
363
364
		return $shares;
365
	}
366
367
368
	/**
369
	 * Get all shares by the given user
370
	 *
371
	 * @param string $userId
372
	 * @param int $shareType
373
	 * @param Node|null $node
374
	 * @param bool $reShares
375
	 * @param int $limit The maximum number of shares to be returned, -1 for all shares
376
	 * @param int $offset
377
	 *
378
	 * @return Share[]
379
	 */
380
	public function getSharesBy($userId, $shareType, $node, $reShares, $limit, $offset) {
381
		$qb = $this->getBaseSelectSql();
382
383
		if ($node === null) {
384
			$this->limitToShareOwner($qb, $userId, $reShares);
385
		} else {
386
			$this->limitToFiles($qb, $node->getId());
387
		}
388
389
		$this->limitToPage($qb, $limit, $offset);
390
		$cursor = $qb->execute();
391
392
		$shares = [];
393
		while ($data = $cursor->fetch()) {
394
			$shares[] = $this->createShareObject($this->editShareEntry($data));
395
		}
396
		$cursor->closeCursor();
397
398
		return $shares;
399
	}
400
401
402
	/**
403
	 * returns a better formatted string to display more information about
404
	 * the circle to the Sharing UI
405
	 *
406
	 * @param $data
407
	 *
408
	 * @return array<string,string>
409
	 * @throws NoUserException
410
	 */
411
	private function editShareEntry($data) {
412
		$data['share_with'] =
413
			sprintf(
414
				'%s (%s, %s) [%s]', $data['circle_name'],
415
				Circle::TypeLongString($data['circle_type']),
416
				$this->miscService->getDisplayName($data['circle_owner']), $data['share_with']
417
			);
418
419
420
		return $data;
421
	}
422
423
424
	/**
425
	 * Get share by its id
426
	 *
427
	 * @param int $shareId
428
	 * @param string|null $recipientId
429
	 *
430
	 * @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...
431
	 * @throws ShareNotFound
432
	 */
433
	public function getShareById($shareId, $recipientId = null) {
434
		$qb = $this->getBaseSelectSql();
435
436
		$this->limitToShare($qb, $shareId);
437
438
		$cursor = $qb->execute();
439
		$data = $cursor->fetch();
440
		$cursor->closeCursor();
441
442
		if ($data === false) {
443
			throw new ShareNotFound();
444
		}
445
446
		return $this->createShareObject($data);
447
	}
448
449
450
	/**
451
	 * Get shares for a given path
452
	 *
453
	 * @param Node $path
454
	 *
455
	 * @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...
456
	 */
457 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...
458
		$qb = $this->getBaseSelectSql();
459
		$this->limitToFiles($qb, [$path->getId()]);
460
		$cursor = $qb->execute();
461
462
		$shares = [];
463
		while ($data = $cursor->fetch()) {
464
			$shares[] = $this->createShareObject($data);
465
		}
466
		$cursor->closeCursor();
467
468
		return $shares;
469
	}
470
471
472
	/**
473
	 * Get shared with the given user
474
	 *
475
	 * @param string $userId get shares where this user is the recipient
476
	 * @param int $shareType
477
	 * @param Node|null $node
478
	 * @param int $limit The max number of entries returned, -1 for all
479
	 * @param int $offset
480
	 *
481
	 * @return IShare[]
482
	 */
483
	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
484
485
		$shares = $this->getSharedWithCircleMembers($userId, $shareType, $node, $limit, $offset);
486
487
		return $shares;
488
	}
489
490
491
	/**
492
	 * @param string $userId
493
	 * @param $shareType
494
	 * @param Node $node
495
	 * @param int $limit
496
	 * @param int $offset
497
	 *
498
	 * @return IShare[]
499
	 */
500
	private function getSharedWithCircleMembers($userId, $shareType, $node, $limit, $offset) {
501
502
		$qb = $this->getCompleteSelectSql();
503
		$this->linkToFileCache($qb, $userId);
504
		$this->limitToPage($qb, $limit, $offset);
505
506
		if ($node !== null) {
507
			$this->limitToFiles($qb, [$node->getId()]);
508
		}
509
510
		$this->linkToMember($qb, $userId, $this->configService->isLinkedGroupsAllowed());
511
512
		$cursor = $qb->execute();
513
514
		$shares = [];
515
		while ($data = $cursor->fetch()) {
516
			self::editShareFromParentEntry($data);
517
			if (self::isAccessibleResult($data)) {
518
				$shares[] = $this->createShareObject($data);
519
			}
520
		}
521
		$cursor->closeCursor();
522
523
		return $shares;
524
	}
525
526
527
	/**
528
	 * Get a share by token
529
	 *
530
	 * @param string $token
531
	 *
532
	 * @return IShare
533
	 * @throws ShareNotFound
534
	 * @deprecated - use local querybuilder lib instead
535
	 */
536
	public function getShareByToken($token) {
537
		$qb = $this->dbConnection->getQueryBuilder();
538
539
		$this->miscService->log("Opening share by token '#" . $token . "'", 0);
540
541
		$cursor = $qb->select('*')
542
					 ->from('share')
543
					 ->where(
544
						 $qb->expr()
545
							->eq(
546
								'share_type',
547
								$qb->createNamedParameter(\OCP\Share::SHARE_TYPE_CIRCLE)
548
							)
549
					 )
550
					 ->andWhere(
551
						 $qb->expr()
552
							->eq('token', $qb->createNamedParameter($token))
553
					 )
554
					 ->execute();
555
556
		$data = $cursor->fetch();
557
558
		if ($data === false) {
559
			$this->miscService->log('data is false - checking personal token', 0);
560
			try {
561
				$data = $this->getShareByPersonalToken($token);
562
			} catch (\Exception $e) {
563
				$this->miscService->log("Share '#" . $token . "' not found.", 0);
564
				throw new ShareNotFound('Share not found', $this->l10n->t('Could not find share'));
565
			}
566
		}
567
568
		try {
569
			$share = $this->createShareObject($data);
570
		} 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...
571
			$this->miscService->log(
572
				"Share Object '#" . $token . "' not created. " . json_encode($data), 0
573
			);
574
			throw new ShareNotFound('Share not found', $this->l10n->t('Could not find share'));
575
		}
576
577
		return $share;
578
	}
579
580
581
	/**
582
	 * @param string $token
583
	 *
584
	 * @return array
585
	 * @throws ShareNotFound
586
	 */
587
	private function getShareByPersonalToken(string $token) {
588
		$qb = $this->dbConnection->getQueryBuilder();
589
590
		$qb = $qb->select('s.*')
591
				 ->selectAlias('ct.password', 'personal_password')
592
				 ->selectAlias('ct.circle_id', 'personal_circle_id')
593
				 ->selectAlias('ct.user_id', 'personal_user_id')
594
				 ->from('share', 's')
595
				 ->from('circles_tokens', 'ct')
596
				 ->where(
597
					 $qb->expr()
598
						->eq(
599
							's.share_type',
600
							$qb->createNamedParameter(\OCP\Share::SHARE_TYPE_CIRCLE)
601
						)
602
				 )
603
				 ->andWhere(
604
					 $qb->expr()
605
						->eq('ct.token', $qb->createNamedParameter($token))
606
				 )
607
				 ->andWhere(
608
					 $qb->expr()
609
						->eq('ct.share_id', 's.id')
610
				 );
611
		$cursor = $qb->execute();
612
613
		$data = $cursor->fetch();
614
		if ($data === false) {
615
			throw new ShareNotFound('personal check not found');
616
		}
617
618
		$member = null;
619
		try {
620
			$member = $this->membersService->getMember(
621
				$data['personal_circle_id'], $data['personal_user_id'], Member::TYPE_MAIL, true
622
			);
623
		} catch (\Exception $e) {
624
			$this->miscService->log('__ no 1 ' . $e->getMessage());
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(string $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