Completed
Pull Request — master (#32767)
by Victor
09:50
created

Share20OcsController::formatShare()   F

Complexity

Conditions 19
Paths 1176

Size

Total Lines 90

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
nc 1176
nop 2
dl 0
loc 90
rs 0.3499
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
 * @author Viktar Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2018, ownCloud GmbH
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace OCA\Files_Sharing\Controller;
23
24
use OCP\AppFramework\OCSController;
25
use OCP\Files\IRootFolder;
26
use OCP\Files\NotFoundException;
27
use OCP\IConfig;
28
use OCP\IGroupManager;
29
use OCP\IL10N;
30
use OCP\IRequest;
31
use OCP\IURLGenerator;
32
use OCP\IUser;
33
use OCP\IUserManager;
34
use OCP\Lock\ILockingProvider;
35
use OCP\Lock\LockedException;
36
use OCP\Share\Exceptions\GenericShareException;
37
use OCP\Share\Exceptions\ShareNotFound;
38
use OCP\Share\IManager;
39
use OCP\Share\IShare;
40
use OCA\Files_Sharing\Service\NotificationPublisher;
41
use OCA\Files_Sharing\Helper;
42
use OCA\Files_Sharing\SharingBlacklist;
43
use Symfony\Component\EventDispatcher\EventDispatcher;
44
use Symfony\Component\EventDispatcher\GenericEvent;
45
46
/**
47
 * Class Share20OcsController
48
 *
49
 * @package OCA\Files_Sharing\Controller
50
 */
51
class Share20OcsController extends OCSController {
52
	/** @var IManager */
53
	private $shareManager;
54
	/** @var IGroupManager */
55
	private $groupManager;
56
	/** @var IUserManager */
57
	private $userManager;
58
	/** @var IRootFolder */
59
	private $rootFolder;
60
	/** @var IURLGenerator */
61
	private $urlGenerator;
62
	/** @var IUser */
63
	private $currentUser;
64
	/** @var IL10N */
65
	private $l;
66
	/** @var IConfig */
67
	private $config;
68
	/** @var NotificationPublisher */
69
	private $notificationPublisher;
70
	/** @var EventDispatcher  */
71
	private $eventDispatcher;
72
	/** @var SharingBlacklist */
73
	private $sharingBlacklist;
74
75
	/**
76
	 * @var string
77
	 */
78
	private $additionalInfoField;
79
80
	public function __construct(
81
		$appName,
82
		IRequest $request,
83
		IManager $shareManager,
84
		IGroupManager $groupManager,
85
		IUserManager $userManager,
86
		IRootFolder $rootFolder,
87
		IURLGenerator $urlGenerator,
88
		IUser $currentUser,
89
		IL10N $l10n,
90
		IConfig $config,
91
		NotificationPublisher $notificationPublisher,
92
		EventDispatcher $eventDispatcher,
93
		SharingBlacklist $sharingBlacklist
94
	) {
95
		parent::__construct($appName, $request);
96
		$this->request = $request;
97
		$this->shareManager = $shareManager;
98
		$this->groupManager = $groupManager;
99
		$this->userManager = $userManager;
100
		$this->rootFolder = $rootFolder;
101
		$this->urlGenerator = $urlGenerator;
102
		$this->currentUser = $currentUser;
103
		$this->l = $l10n;
104
		$this->config = $config;
105
		$this->notificationPublisher = $notificationPublisher;
106
		$this->eventDispatcher = $eventDispatcher;
107
		$this->sharingBlacklist = $sharingBlacklist;
108
		$this->additionalInfoField = $this->config->getAppValue('core', 'user_additional_info_field', '');
109
	}
110
111
	/**
112
	 * Returns the additional info to display behind the display name as configured.
113
	 *
114
	 * @param IUser $user user for which to retrieve the additional info
115
	 * @return string|null additional info or null if none to be displayed
116
	 */
117 View Code Duplication
	private function getAdditionalUserInfo(IUser $user) {
118
		if ($this->additionalInfoField === 'email') {
119
			return $user->getEMailAddress();
120
		} elseif ($this->additionalInfoField === 'id') {
121
			return $user->getUID();
122
		}
123
		return null;
124
	}
125
126
	/**
127
	 * Convert an IShare to an array for OCS output
128
	 *
129
	 * @param \OCP\Share\IShare $share
130
	 * @param bool $received whether it's formatting received shares
131
	 * @return array
132
	 * @throws NotFoundException In case the node can't be resolved.
133
	 */
134
	protected function formatShare(\OCP\Share\IShare $share, $received = false) {
135
		$sharedBy = $this->userManager->get($share->getSharedBy());
136
		$shareOwner = $this->userManager->get($share->getShareOwner());
137
138
		$result = [
139
			'id' => $share->getId(),
140
			'share_type' => $share->getShareType(),
141
			'uid_owner' => $share->getSharedBy(),
142
			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
143
			'permissions' => $share->getPermissions(),
144
			'stime' => $share->getShareTime() ? $share->getShareTime()->getTimestamp() : null,
145
			'parent' => null,
146
			'expiration' => null,
147
			'token' => null,
148
			'uid_file_owner' => $share->getShareOwner(),
149
			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner()
150
		];
151
152
		if ($received) {
153
			// also add state
154
			$result['state'] = $share->getState();
155
156
			// can only fetch path info if mounted already or if owner
157
			if ($share->getState() === \OCP\Share::STATE_ACCEPTED || $share->getShareOwner() === $this->currentUser->getUID()) {
158
				$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
159
			} else {
160
				// need to go through owner user for pending shares
161
				$userFolder = $this->rootFolder->getUserFolder($share->getShareOwner());
162
			}
163
		} else {
164
			$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
165
		}
166
167
		$nodes = $userFolder->getById($share->getNodeId());
168
169
		if (empty($nodes)) {
170
			throw new NotFoundException();
171
		}
172
173
		$node = $nodes[0];
174
175
		$result['path'] = $userFolder->getRelativePath($node->getPath());
176
		if ($node instanceof \OCP\Files\Folder) {
177
			$result['item_type'] = 'folder';
178
		} else {
179
			$result['item_type'] = 'file';
180
		}
181
		$result['mimetype'] = $node->getMimeType();
182
		$result['storage_id'] = $node->getStorage()->getId();
183
		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
184
		$result['item_source'] = \strval($node->getId());
185
		$result['file_source'] = \strval($node->getId());
186
		$result['file_parent'] = \strval($node->getParent()->getId());
187
		$result['file_target'] = $share->getTarget();
188
189
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
190
			$sharedWith = $this->userManager->get($share->getSharedWith());
191
			$result['share_with'] = $share->getSharedWith();
192
			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
193
			if ($sharedWith !== null) {
194
				$result['share_with_additional_info'] = $this->getAdditionalUserInfo($sharedWith);
195
			}
196
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
197
			$group = $this->groupManager->get($share->getSharedWith());
198
			$result['share_with'] = $share->getSharedWith();
199
			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
200
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
201
			$result['share_with'] = $share->getPassword();
202
			$result['share_with_displayname'] = $share->getPassword();
203
			$result['name'] = $share->getName();
204
205
			$result['token'] = $share->getToken();
206
			if ($share->getToken() !== null) {
207
				$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
208
			}
209
210
			$expiration = $share->getExpirationDate();
211
			if ($expiration !== null) {
212
				$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
213
			}
214
		} elseif ($share->getShareType() === \OCP\Share::SHARE_TYPE_REMOTE) {
215
			$result['share_with'] = $share->getSharedWith();
216
			$result['share_with_displayname'] = $share->getSharedWith();
217
			$result['token'] = $share->getToken();
218
		}
219
220
		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
221
222
		return $result;
223
	}
224
225
	/**
226
	 * Get a specific share by id
227
	 *
228
	 * @NoCSRFRequired
229
	 *
230
	 * @param string $id
231
	 * @return \OC\OCS\Result
232
	 */
233
	public function getShare($id) {
234
		if (!$this->shareManager->shareApiEnabled()) {
235
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
236
		}
237
238
		try {
239
			$share = $this->getShareById($id);
240
		} catch (ShareNotFound $e) {
241
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
242
		}
243
244
		if ($this->canAccessShare($share)) {
245
			try {
246
				$share = $this->formatShare($share);
247
				return new \OC\OCS\Result([$share]);
248
			} catch (NotFoundException $e) {
249
				//Fall trough
250
			}
251
		}
252
253
		return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
254
	}
255
256
	/**
257
	 * Delete a share
258
	 *
259
	 * @NoCSRFRequired
260
	 *
261
	 * @param string $id
262
	 * @return \OC\OCS\Result
263
	 */
264
	public function deleteShare($id) {
265
		if (!$this->shareManager->shareApiEnabled()) {
266
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
267
		}
268
269
		try {
270
			$share = $this->getShareById($id);
271
		} catch (ShareNotFound $e) {
272
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
273
		}
274
275
		try {
276
			$share->getNode()->lock(ILockingProvider::LOCK_SHARED);
277
		} catch (LockedException $e) {
278
			return new \OC\OCS\Result(null, 404, 'could not delete share');
279
		}
280
281 View Code Duplication
		if (!$this->canAccessShare($share)) {
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...
282
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
283
			return new \OC\OCS\Result(null, 404, $this->l->t('Could not delete share'));
284
		}
285
286
		$this->shareManager->deleteShare($share);
287
288
		$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
289
290
		return new \OC\OCS\Result();
291
	}
292
293
	/**
294
	 * @NoCSRFRequired
295
	 *
296
	 * @return \OC\OCS\Result
297
	 */
298
	public function createShare() {
299
		$share = $this->shareManager->newShare();
300
301
		if (!$this->shareManager->shareApiEnabled()) {
302
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
303
		}
304
305
		$name = $this->request->getParam('name', null);
306
307
		// Verify path
308
		$path = $this->request->getParam('path', null);
309
		if ($path === null) {
310
			return new \OC\OCS\Result(null, 404, $this->l->t('Please specify a file or folder path'));
311
		}
312
313
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
314
315
		try {
316
			$path = $userFolder->get($path);
317
		} catch (NotFoundException $e) {
318
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong path, file/folder doesn\'t exist'));
319
		}
320
321
		$share->setNode($path);
322
323
		try {
324
			$share->getNode()->lock(ILockingProvider::LOCK_SHARED);
325
		} catch (LockedException $e) {
326
			return new \OC\OCS\Result(null, 404, 'Could not create share');
327
		}
328
329
		$shareType = (int)$this->request->getParam('shareType', '-1');
330
331
		// Parse permissions (if available)
332
		$permissions = $this->request->getParam('permissions', null);
333
		if ($permissions === null) {
334
			if ($shareType !== \OCP\Share::SHARE_TYPE_LINK) {
335
				$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', \OCP\Constants::PERMISSION_ALL);
336
				$permissions |= \OCP\Constants::PERMISSION_READ;
337
			} else {
338
				$permissions = \OCP\Constants::PERMISSION_ALL;
339
			}
340
		} else {
341
			$permissions = (int)$permissions;
342
		}
343
344
		if ($permissions < 0 || $permissions > \OCP\Constants::PERMISSION_ALL) {
345
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
346
			return new \OC\OCS\Result(null, 404, 'invalid permissions');
347
		}
348
349
		if ($permissions === 0) {
350
			return new \OC\OCS\Result(null, 400, $this->l->t('Cannot remove all permissions'));
351
		}
352
353
		// link shares can have create-only without read (anonymous upload)
354
		if ($shareType !== \OCP\Share::SHARE_TYPE_LINK && $permissions !== \OCP\Constants::PERMISSION_CREATE) {
355
			// Shares always require read permissions
356
			$permissions |= \OCP\Constants::PERMISSION_READ;
357
		}
358
359
		if ($path instanceof \OCP\Files\File) {
360
			// Single file shares should never have delete or create permissions
361
			$permissions &= ~\OCP\Constants::PERMISSION_DELETE;
362
			$permissions &= ~\OCP\Constants::PERMISSION_CREATE;
363
		}
364
365
		/*
366
		 * Hack for https://github.com/owncloud/core/issues/22587
367
		 * We check the permissions via webdav. But the permissions of the mount point
368
		 * do not equal the share permissions. Here we fix that for federated mounts.
369
		 */
370
		if ($path->getStorage()->instanceOfStorage('OCA\Files_Sharing\External\Storage')) {
371
			$permissions &= ~($permissions & ~$path->getPermissions());
372
		}
373
374
		$shareWith = $this->request->getParam('shareWith', null);
375
376
		$autoAccept = $this->config->getAppValue('core', 'shareapi_auto_accept_share', 'yes') === 'yes';
377
		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
378
			// Valid user is required to share
379
			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
380
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
381
				return new \OC\OCS\Result(null, 404, $this->l->t('Please specify a valid user'));
382
			}
383
			$share->setSharedWith($shareWith);
384
			$share->setPermissions($permissions);
385
			if ($autoAccept) {
386
				$share->setState(\OCP\Share::STATE_ACCEPTED);
387
			} else {
388
				$share->setState(\OCP\Share::STATE_PENDING);
389
			}
390
		} elseif ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
391
			if (!$this->shareManager->allowGroupSharing()) {
392
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
393
				return new \OC\OCS\Result(null, 404, $this->l->t('Group sharing is disabled by the administrator'));
394
			}
395
396
			// Valid group is required to share
397
			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
398
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
399
				return new \OC\OCS\Result(null, 404, $this->l->t('Please specify a valid group'));
400
			}
401
			if ($this->sharingBlacklist->isGroupBlacklisted($this->groupManager->get($shareWith))) {
402
				return new \OC\OCS\Result(null, 403, $this->l->t('The group is blacklisted for sharing'));
403
			}
404
			$share->setSharedWith($shareWith);
405
			$share->setPermissions($permissions);
406
			if ($autoAccept) {
407
				$share->setState(\OCP\Share::STATE_ACCEPTED);
408
			} else {
409
				$share->setState(\OCP\Share::STATE_PENDING);
410
			}
411
		} elseif ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
412
			//Can we even share links?
413
			if (!$this->shareManager->shareApiAllowLinks()) {
414
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
415
				return new \OC\OCS\Result(null, 404, $this->l->t('Public link sharing is disabled by the administrator'));
416
			}
417
418
			// legacy way, expecting that this won't be used together with "create-only" shares
419
			$publicUpload = $this->request->getParam('publicUpload', null);
420
			// a few permission checks
421 View Code Duplication
			if ($publicUpload === 'true' || $permissions === \OCP\Constants::PERMISSION_CREATE) {
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...
422
				// Check if public upload is allowed
423
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
424
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
425
					return new \OC\OCS\Result(null, 403, $this->l->t('Public upload disabled by the administrator'));
426
				}
427
428
				// Public upload can only be set for folders
429
				if ($path instanceof \OCP\Files\File) {
430
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
431
					return new \OC\OCS\Result(null, 404, $this->l->t('Public upload is only possible for publicly shared folders'));
432
				}
433
			}
434
435
			// convert to permissions
436
			if ($publicUpload === 'true') {
437
				$share->setPermissions(
438
					\OCP\Constants::PERMISSION_READ |
439
					\OCP\Constants::PERMISSION_CREATE |
440
					\OCP\Constants::PERMISSION_UPDATE |
441
					\OCP\Constants::PERMISSION_DELETE
442
				);
443
			} elseif ($permissions === \OCP\Constants::PERMISSION_CREATE ||
444
				$permissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)) {
445
				$share->setPermissions($permissions);
446
			} else {
447
				// because when "publicUpload" is passed usually no permissions are set,
448
				// which defaults to ALL. But in the case of link shares we default to READ...
449
				$share->setPermissions(\OCP\Constants::PERMISSION_READ);
450
			}
451
452
			// set name only if passed as parameter, empty string is allowed
453
			if ($name !== null) {
454
				$share->setName($name);
455
			}
456
457
			// Set password
458
			$password = $this->request->getParam('password', '');
459
460
			if ($password !== '') {
461
				$share->setPassword($password);
462
			}
463
464
			//Expire date
465
			$expireDate = $this->request->getParam('expireDate', '');
466
467
			if ($expireDate !== '') {
468
				try {
469
					$expireDate = $this->parseDate($expireDate);
470
					$share->setExpirationDate($expireDate);
471
				} catch (\Exception $e) {
472
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
473
					return new \OC\OCS\Result(null, 404, $this->l->t('Invalid date, date format must be YYYY-MM-DD'));
474
				}
475
			}
476
		} elseif ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
477
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
478
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
479
				return new \OC\OCS\Result(null, 403, $this->l->t('Sharing %s failed because the back end does not allow shares from type %s', [$path->getPath(), $shareType]));
480
			}
481
482
			$share->setSharedWith($shareWith);
483
			$share->setPermissions($permissions);
484 View Code Duplication
		} else {
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...
485
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
486
			return new \OC\OCS\Result(null, 400, $this->l->t('Unknown share type'));
487
		}
488
489
		$share->setShareType($shareType);
490
		$share->setSharedBy($this->currentUser->getUID());
491
492
		try {
493
			$share = $this->shareManager->createShare($share);
494
		} catch (GenericShareException $e) {
495
			$code = $e->getCode() === 0 ? 403 : $e->getCode();
496
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
497
			return new \OC\OCS\Result(null, $code, $e->getHint());
498
		} catch (\Exception $e) {
499
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
500
			return new \OC\OCS\Result(null, 403, $e->getMessage());
501
		}
502
503
		$share->getNode()->unlock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
504
505
		$formattedShareAfterCreate = $this->formatShare($share);
506
507
		return new \OC\OCS\Result($formattedShareAfterCreate);
508
	}
509
510
	/**
511
	 * @param \OCP\Files\File|\OCP\Files\Folder $node
512
	 * @param boolean $includeTags include tags in response
513
	 * @param int|null $stateFilter state filter or empty for all, defaults to 0 (accepted)
514
	 * @return \OC\OCS\Result
515
	 */
516
	private function getSharedWithMe($node = null, $includeTags, $stateFilter = 0) {
517
		$userShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
518
		$groupShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
519
520
		$shares = \array_merge($userShares, $groupShares);
521
522
		$shares = \array_filter($shares, function (IShare $share) {
523
			return $share->getShareOwner() !== $this->currentUser->getUID();
524
		});
525
526
		$formatted = [];
527
		foreach ($shares as $share) {
528
			if (($stateFilter === null || $share->getState() === $stateFilter) &&
529
				$this->canAccessShare($share)) {
530
				try {
531
					$formatted[] = $this->formatShare($share, true);
532
				} catch (NotFoundException $e) {
533
					// Ignore this share
534
				}
535
			}
536
		}
537
538
		if ($includeTags) {
539
			$formatted = \OCA\Files\Helper::populateTags($formatted, 'file_source');
540
		}
541
542
		return new \OC\OCS\Result($formatted);
543
	}
544
545
	/**
546
	 * @param \OCP\Files\Folder $folder
547
	 * @return \OC\OCS\Result
548
	 */
549
	private function getSharesInDir($folder) {
550
		if (!($folder instanceof \OCP\Files\Folder)) {
551
			return new \OC\OCS\Result(null, 400, $this->l->t('Not a directory'));
552
		}
553
554
		$nodes = $folder->getDirectoryListing();
555
		/** @var \OCP\Share\IShare[] $shares */
556
		$shares = [];
557
		foreach ($nodes as $node) {
558
			$shares = \array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, false, -1, 0));
559
			$shares = \array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, false, -1, 0));
560
			$shares = \array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $node, false, -1, 0));
561
			if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
562
				$shares = \array_merge($shares, $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_REMOTE, $node, false, -1, 0));
563
			}
564
		}
565
566
		$formatted = [];
567
		foreach ($shares as $share) {
568
			try {
569
				$formatted[] = $this->formatShare($share);
570
			} catch (NotFoundException $e) {
571
				//Ignore this share
572
			}
573
		}
574
575
		return new \OC\OCS\Result($formatted);
576
	}
577
578
	/**
579
	 * The getShares function.
580
	 *
581
	 * @NoCSRFRequired
582
	 *
583
	 * - Get shares by the current user
584
	 * - Get shares by the current user and reshares (?reshares=true)
585
	 * - Get shares with the current user (?shared_with_me=true)
586
	 * - Get shares for a specific path (?path=...)
587
	 * - Get all shares in a folder (?subfiles=true&path=..)
588
	 *
589
	 * @return \OC\OCS\Result
590
	 */
591
	public function getShares() {
592
		if (!$this->shareManager->shareApiEnabled()) {
593
			return new \OC\OCS\Result();
594
		}
595
596
		$sharedWithMe = $this->request->getParam('shared_with_me', null);
597
		$reshares = $this->request->getParam('reshares', null);
598
		$subfiles = $this->request->getParam('subfiles');
599
		$path = $this->request->getParam('path', null);
600
601
		$includeTags = $this->request->getParam('include_tags', false);
602
603
		if ($path !== null) {
604
			$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
605
			try {
606
				$path = $userFolder->get($path);
607
				$path->lock(ILockingProvider::LOCK_SHARED);
608
			} catch (\OCP\Files\NotFoundException $e) {
609
				return new \OC\OCS\Result(null, 404, $this->l->t('Wrong path, file/folder doesn\'t exist'));
610
			} catch (LockedException $e) {
611
				return new \OC\OCS\Result(null, 404, $this->l->t('Could not lock path'));
612
			}
613
		}
614
615
		if ($sharedWithMe === 'true') {
616
			$stateFilter = $this->request->getParam('state', \OCP\Share::STATE_ACCEPTED);
617
			if ($stateFilter === '') {
618
				$stateFilter = \OCP\Share::STATE_ACCEPTED;
619
			} elseif ($stateFilter === 'all') {
620
				$stateFilter = null; // which means all
621
			} else {
622
				$stateFilter = (int)$stateFilter;
623
			}
624
			$result = $this->getSharedWithMe($path, $includeTags, $stateFilter);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type object<OCP\Files\Node>; however, OCA\Files_Sharing\Contro...ller::getSharedWithMe() does only seem to accept object<OCP\Files\File>|o...<OCP\Files\Folder>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
625
			if ($path !== null) {
626
				$path->unlock(ILockingProvider::LOCK_SHARED);
627
			}
628
			return $result;
629
		}
630
631
		if ($subfiles === 'true') {
632
			$result = $this->getSharesInDir($path);
0 ignored issues
show
Documentation introduced by
$path is of type object<OCP\Files\Node>|null, but the function expects a object<OCP\Files\Folder>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
633
			if ($path !== null) {
634
				$path->unlock(ILockingProvider::LOCK_SHARED);
635
			}
636
			return $result;
637
		}
638
639
		if ($reshares === 'true') {
640
			$reshares = true;
641
		} else {
642
			$reshares = false;
643
		}
644
645
		// Get all shares
646
		$userShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
647
		$groupShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
648
		$linkShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
649
		$shares = \array_merge($userShares, $groupShares, $linkShares);
650
651
		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
652
			$federatedShares = $this->shareManager->getSharesBy($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
653
			$shares = \array_merge($shares, $federatedShares);
654
		}
655
656
		$formatted = [];
657
		foreach ($shares as $share) {
658
			try {
659
				$formatted[] = $this->formatShare($share);
660
			} catch (NotFoundException $e) {
661
				//Ignore share
662
			}
663
		}
664
665
		if ($includeTags) {
666
			$formatted = \OCA\Files\Helper::populateTags($formatted, 'file_source');
667
		}
668
669
		if ($path !== null) {
670
			$path->unlock(ILockingProvider::LOCK_SHARED);
671
		}
672
673
		return new \OC\OCS\Result($formatted);
674
	}
675
676
	/**
677
	 * @NoCSRFRequired
678
	 *
679
	 * @param int $id
680
	 * @return \OC\OCS\Result
681
	 */
682
	public function updateShare($id) {
683
		if (!$this->shareManager->shareApiEnabled()) {
684
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
685
		}
686
687
		try {
688
			$share = $this->getShareById($id);
689
		} catch (ShareNotFound $e) {
690
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
691
		}
692
693
		$share->getNode()->lock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
694
695 View Code Duplication
		if (!$this->canAccessShare($share)) {
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...
696
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
697
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
698
		}
699
700
		$permissions = $this->request->getParam('permissions', null);
701
		$password = $this->request->getParam('password', null);
702
		$publicUpload = $this->request->getParam('publicUpload', null);
703
		$expireDate = $this->request->getParam('expireDate', null);
704
		$name = $this->request->getParam('name', null);
705
706
		/*
707
		 * expirationdate, password and publicUpload only make sense for link shares
708
		 */
709
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
710
			if ($permissions === null && $password === null && $publicUpload === null && $expireDate === null && $name === null) {
711
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
712
				return new \OC\OCS\Result(null, 400, 'Wrong or no update parameter given');
713
			}
714
715
			$newPermissions = null;
716
			if ($publicUpload === 'true') {
717
				$newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
718
			} elseif ($publicUpload === 'false') {
719
				$newPermissions = \OCP\Constants::PERMISSION_READ;
720
			}
721
722
			if ($permissions !== null) {
723
				$newPermissions = (int)$permissions;
724
			}
725
726
			if ($newPermissions !== null &&
727
				$newPermissions !== \OCP\Constants::PERMISSION_READ &&
728
				$newPermissions !== \OCP\Constants::PERMISSION_CREATE &&
729
				// legacy
730
				$newPermissions !== (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE) &&
731
				// correct
732
				$newPermissions !== (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)
733
			) {
734
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
735
				return new \OC\OCS\Result(null, 400, $this->l->t('Can\'t change permissions for public share links'));
736
			}
737
738
			if (
739
				// legacy
740
				$newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE) ||
741
				// correct
742
				$newPermissions === (\OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE)
743
			) {
744
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
745
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
746
					return new \OC\OCS\Result(null, 403, $this->l->t('Public upload disabled by the administrator'));
747
				}
748
749
				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
750
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
751
					return new \OC\OCS\Result(null, 400, $this->l->t('Public upload is only possible for publicly shared folders'));
752
				}
753
754
				// normalize to correct public upload permissions
755
				$newPermissions = \OCP\Constants::PERMISSION_READ | \OCP\Constants::PERMISSION_CREATE | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
756
			}
757
758
			// create-only (upload-only)
759 View Code Duplication
			if (
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...
760
				$newPermissions === \OCP\Constants::PERMISSION_CREATE
761
			) {
762
				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
763
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
764
					return new \OC\OCS\Result(null, 403, $this->l->t('Public upload disabled by the administrator'));
765
				}
766
767
				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
768
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
769
					return new \OC\OCS\Result(null, 400, $this->l->t('Public upload is only possible for publicly shared folders'));
770
				}
771
			}
772
773
			// set name only if passed as parameter, empty string is allowed
774
			if ($name !== null) {
775
				$oldname = $share->getName();
776
				$share->setName($name);
777
			}
778
779
			if ($newPermissions !== null) {
780
				$share->setPermissions($newPermissions);
781
				$permissions = $newPermissions;
782
			}
783
784
			if ($expireDate === '') {
785
				$share->setExpirationDate(null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<DateTime>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
786
			} elseif ($expireDate !== null) {
787
				try {
788
					$expireDate = $this->parseDate($expireDate);
789
				} catch (\Exception $e) {
790
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
791
					return new \OC\OCS\Result(null, 400, $e->getMessage());
792
				}
793
				$share->setExpirationDate($expireDate);
794
			}
795
796
			if ($password === '') {
797
				$share->setPassword(null);
798
			} elseif ($password !== null) {
799
				$share->setPassword($password);
800
			}
801
		} else {
802
			// For other shares only permissions is valid.
803
			if ($permissions === null) {
804
				$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
805
				return new \OC\OCS\Result(null, 400, $this->l->t('Wrong or no update parameter given'));
806
			} else {
807
				$permissions = (int)$permissions;
808
				$share->setPermissions($permissions);
809
			}
810
		}
811
812
		if ($permissions !== null && $share->getShareOwner() !== $this->currentUser->getUID()) {
813
			/* Check if this is an incoming share */
814
			$incomingShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $share->getNode(), -1, 0);
815
			$incomingShares = \array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0));
816
817
			if (!empty($incomingShares)) {
818
				$maxPermissions = 0;
819
				foreach ($incomingShares as $incomingShare) {
820
					$maxPermissions |= $incomingShare->getPermissions();
821
				}
822
823
				if ($share->getPermissions() & ~$maxPermissions) {
824
					$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
825
					return new \OC\OCS\Result(null, 404, $this->l->t('Cannot increase permissions'));
826
				}
827
			}
828
		}
829
830
		if ($share->getPermissions() === 0) {
831
			return new \OC\OCS\Result(null, 400, $this->l->t('Cannot remove all permissions'));
832
		}
833
834
		try {
835
			$share = $this->shareManager->updateShare($share);
836
		} catch (\Exception $e) {
837
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
838
			return new \OC\OCS\Result(null, 400, $e->getMessage());
839
		}
840
841
		$share->getNode()->unlock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
842
843
		return new \OC\OCS\Result($this->formatShare($share));
844
	}
845
846
	/**
847
	 * @NoCSRFRequired
848
	 *
849
	 * @param int $id
850
	 * @return \OC\OCS\Result
851
	 */
852
	public function acceptShare($id) {
853
		return $this->updateShareState($id, \OCP\Share::STATE_ACCEPTED);
854
	}
855
856
	/**
857
	 * @NoCSRFRequired
858
	 *
859
	 * @param int $id
860
	 * @return \OC\OCS\Result
861
	 */
862
	public function declineShare($id) {
863
		return $this->updateShareState($id, \OCP\Share::STATE_REJECTED);
864
	}
865
866
	/**
867
	 * @param $id
868
	 * @param $state
869
	 * @return \OC\OCS\Result
870
	 */
871
	private function updateShareState($id, $state) {
872
		$eventName = '';
873
		if ($state === \OCP\Share::STATE_ACCEPTED) {
874
			$eventName = 'accept';
875
		} elseif ($state === \OCP\Share::STATE_REJECTED) {
876
			$eventName = 'reject';
877
		}
878
879
		if (!$this->shareManager->shareApiEnabled()) {
880
			return new \OC\OCS\Result(null, 404, $this->l->t('Share API is disabled'));
881
		}
882
883
		try {
884
			$share = $this->getShareById($id, $this->currentUser->getUID());
885
			$this->eventDispatcher->dispatch('share.before' . $eventName, new GenericEvent(null, ['share' => $share]));
886
		} catch (ShareNotFound $e) {
887
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
888
		}
889
890
		$node = $share->getNode();
891
		$node->lock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
892
893
		// this checks that we are either the owner or recipient
894 View Code Duplication
		if (!$this->canAccessShare($share)) {
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...
895
			$node->unlock(ILockingProvider::LOCK_SHARED);
896
			return new \OC\OCS\Result(null, 404, $this->l->t('Wrong share ID, share doesn\'t exist'));
897
		}
898
899
		// only recipient can accept/reject share
900
		if ($share->getShareOwner() === $this->currentUser->getUID() ||
901
			$share->getSharedBy() === $this->currentUser->getUID()) {
902
			$node->unlock(ILockingProvider::LOCK_SHARED);
903
			return new \OC\OCS\Result(null, 403, $this->l->t('Only recipient can change accepted state'));
904
		}
905
906
		if ($share->getState() === $state) {
907 View Code Duplication
			if ($eventName !== '') {
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...
908
				$this->eventDispatcher->dispatch('share.after' . $eventName, new GenericEvent(null, ['share' => $share]));
909
			}
910
			// if there are no changes in the state, just return the share as if the change was successful
911
			$node->unlock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
912
			return new \OC\OCS\Result([$this->formatShare($share, true)]);
913
		}
914
915
		// we actually want to update all shares related to the node in case there are multiple
916
		// incoming shares for the same node (ex: receiving simultaneously through group share and user share)
917
		$allShares = $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
918
		$allShares = \array_merge($allShares, $this->shareManager->getSharedWith($this->currentUser->getUID(), \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0));
919
920
		// resolve and deduplicate target if accepting
921
		if ($state === \OCP\Share::STATE_ACCEPTED) {
922
			$share = $this->deduplicateShareTarget($share);
923
		}
924
925
		$share->setState($state);
926
927
		try {
928
			foreach ($allShares as $aShare) {
929
				$aShare->setState($share->getState());
930
				$aShare->setTarget($share->getTarget());
931
				$this->shareManager->updateShareForRecipient($aShare, $this->currentUser->getUID());
932
			}
933
		} catch (\Exception $e) {
934
			$share->getNode()->unlock(ILockingProvider::LOCK_SHARED);
935
			return new \OC\OCS\Result(null, 400, $e->getMessage());
936
		}
937
938
		$node->unlock(\OCP\Lock\ILockingProvider::LOCK_SHARED);
939
940
		// FIXME: needs public API!
941
		\OC\Files\Filesystem::tearDown();
942
		// FIXME: trigger mount for user to make sure the new node is mounted already
943
		// before formatShare resolves it
944
		$this->rootFolder->getUserFolder($this->currentUser->getUID());
945
946
		$this->notificationPublisher->discardNotificationForUser($share, $this->currentUser->getUID());
947
948 View Code Duplication
		if ($eventName !== '') {
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...
949
			$this->eventDispatcher->dispatch('share.after' . $eventName, new GenericEvent(null, ['share' => $share]));
950
		}
951
		return new \OC\OCS\Result([$this->formatShare($share, true)]);
952
	}
953
954
	/**
955
	 * Deduplicate the share target in the current user home folder,
956
	 * based on configured share folder
957
	 *
958
	 * @param IShare $share share target to deduplicate
959
	 * @return IShare same share with target updated if necessary
960
	 */
961
	private function deduplicateShareTarget(IShare $share) {
962
		$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
963
		$mountPoint = \basename($share->getTarget());
964
		$parentDir = \dirname($share->getTarget());
965
		if (!$userFolder->nodeExists($parentDir)) {
966
			$parentDir = Helper::getShareFolder();
967
			$pathAttempt = \OC\Files\Filesystem::normalizePath($parentDir . '/' . $share->getTarget());
968
		} else {
969
			$pathAttempt = \OC\Files\Filesystem::normalizePath($share->getTarget());
970
		}
971
972
		$pathinfo = \pathinfo($pathAttempt);
973
		$ext = (isset($pathinfo['extension'])) ? '.'.$pathinfo['extension'] : '';
974
		$name = $pathinfo['filename'];
975
976
		$i = 2;
977
		while ($userFolder->nodeExists($pathAttempt)) {
978
			$pathAttempt = \OC\Files\Filesystem::normalizePath($parentDir . '/' . $name . ' ('.$i.')' . $ext);
979
			$i++;
980
		}
981
982
		$share->setTarget($pathAttempt);
983
984
		return $share;
985
	}
986
987
	/**
988
	 * @param \OCP\Share\IShare $share
989
	 * @return bool
990
	 */
991
	protected function canAccessShare(\OCP\Share\IShare $share) {
992
		// A file with permissions 0 can't be accessed by us,
993
		// unless it's a rejected sub-group share in which case we want it visible to let the user accept it again
994
		if ($share->getPermissions() === 0
995
			&& !($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP && $share->getState() === \OCP\Share::STATE_REJECTED)) {
996
			return false;
997
		}
998
999
		// Owner of the file and the sharer of the file can always get share
1000
		if ($share->getShareOwner() === $this->currentUser->getUID() ||
1001
			$share->getSharedBy() === $this->currentUser->getUID()
1002
		) {
1003
			return true;
1004
		}
1005
1006
		// If the share is shared with you (or a group you are a member of)
1007
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER &&
1008
			$share->getSharedWith() === $this->currentUser->getUID()) {
1009
			return true;
1010
		}
1011
1012
		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
1013
			$sharedWith = $this->groupManager->get($share->getSharedWith());
1014
			if ($sharedWith !== null && $sharedWith->inGroup($this->currentUser)) {
1015
				return true;
1016
			}
1017
		}
1018
1019
		return false;
1020
	}
1021
1022
	/**
1023
	 * Make sure that the passed date is valid ISO 8601
1024
	 * So YYYY-MM-DD
1025
	 * If not throw an exception
1026
	 *
1027
	 * @param string $expireDate
1028
	 *
1029
	 * @throws \Exception
1030
	 * @return \DateTime
1031
	 */
1032
	private function parseDate($expireDate) {
1033
		try {
1034
			$date = new \DateTime($expireDate);
1035
		} catch (\Exception $e) {
1036
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1037
		}
1038
1039
		if ($date === false) {
1040
			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1041
		}
1042
1043
		$date->setTime(0, 0, 0);
1044
1045
		return $date;
1046
	}
1047
1048
	/**
1049
	 * Since we have multiple providers but the OCS Share API v1 does
1050
	 * not support this we need to check all backends.
1051
	 *
1052
	 * @param string $id
1053
	 * @return \OCP\Share\IShare
1054
	 * @throws ShareNotFound
1055
	 */
1056
	private function getShareById($id, $recipient = null) {
1057
		$share = null;
1058
1059
		// First check if it is an internal share.
1060
		try {
1061
			$share = $this->shareManager->getShareById('ocinternal:'.$id, $recipient);
1062
		} catch (ShareNotFound $e) {
1063
			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1064
				throw new ShareNotFound();
1065
			}
1066
1067
			$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $recipient);
1068
		}
1069
1070
		return $share;
1071
	}
1072
}
1073