Skip to content

Commit 3870170

Browse files
committed
feat(files_sharing): Implement partial mount providers
Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Signed-off-by: Louis Chmn <louis@chmn.me>
1 parent 0ff8b35 commit 3870170

File tree

6 files changed

+249
-40
lines changed

6 files changed

+249
-40
lines changed

apps/files_sharing/lib/External/MountProvider.php

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use OCP\DB\QueryBuilder\IQueryBuilder;
1414
use OCP\Federation\ICloudIdManager;
1515
use OCP\Files\Config\IMountProvider;
16+
use OCP\Files\Config\IPartialMountProvider;
1617
use OCP\Files\Storage\IStorageFactory;
1718
use OCP\Http\Client\IClientService;
1819
use OCP\ICertificateManager;
@@ -21,7 +22,7 @@
2122
use OCP\Server;
2223
use OCP\Share\IShare;
2324

24-
class MountProvider implements IMountProvider {
25+
class MountProvider implements IMountProvider, IPartialMountProvider {
2526
public const STORAGE = ExternalShareStorage::class;
2627

2728
/**
@@ -69,4 +70,54 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array {
6970
$result->closeCursor();
7071
return $mounts;
7172
}
73+
74+
public function getMountsForPath(
75+
string $MountProvider,
76+
bool $forChildren,
77+
array $mountProviderArgs,
78+
IStorageFactory $loader,
79+
): array {
80+
$user = $mountProviderArgs[0]->mountInfo->getUser();
81+
$userId = $user->getUID();
82+
83+
if (!$forChildren) {
84+
// override path with mount point when fetching without children
85+
$MountProvider = $mountProviderArgs[0]->mountInfo->getMountPoint();
86+
}
87+
88+
// remove /uid/files as the target is stored without
89+
$MountProvider = \substr($MountProvider, \strlen('/' . $userId . '/files'));
90+
// remove trailing slash
91+
$MountProvider = \rtrim($MountProvider, '/');
92+
93+
// make sure trailing slash is present when loading children
94+
if ($forChildren || $MountProvider === '') {
95+
$MountProvider .= '/';
96+
}
97+
98+
$qb = $this->connection->getQueryBuilder();
99+
$qb->select('id', 'remote', 'share_token', 'password', 'mountpoint', 'owner')
100+
->from('share_external')
101+
->where($qb->expr()->eq('user', $qb->createNamedParameter($user->getUID())))
102+
->andWhere($qb->expr()->eq('accepted', $qb->createNamedParameter(IShare::STATUS_ACCEPTED, IQueryBuilder::PARAM_INT)));
103+
104+
if ($forChildren) {
105+
$qb->andWhere($qb->expr()->like('mountpoint', $qb->createNamedParameter($this->connection->escapeLikeParameter($MountProvider) . '_%')));
106+
} else {
107+
$qb->andWhere($qb->expr()->eq('mountpoint', $qb->createNamedParameter($MountProvider)));
108+
}
109+
110+
$result = $qb->executeQuery();
111+
112+
$mounts = [];
113+
while ($row = $result->fetchAssociative()) {
114+
$row['manager'] = $this;
115+
$row['token'] = $row['share_token'];
116+
$mount = $this->getMount($user, $row, $loader);
117+
$mounts[$mount->getMountPoint()] = $mount;
118+
}
119+
$result->closeCursor();
120+
121+
return $mounts;
122+
}
72123
}

apps/files_sharing/lib/MountProvider.php

Lines changed: 84 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use OCP\Cache\CappedMemoryCache;
1515
use OCP\EventDispatcher\IEventDispatcher;
1616
use OCP\Files\Config\IMountProvider;
17+
use OCP\Files\Config\IPartialMountProvider;
1718
use OCP\Files\Mount\IMountManager;
1819
use OCP\Files\Mount\IMountPoint;
1920
use OCP\Files\Storage\IStorageFactory;
@@ -24,9 +25,11 @@
2425
use OCP\Share\IManager;
2526
use OCP\Share\IShare;
2627
use Psr\Log\LoggerInterface;
28+
use RecursiveIteratorIterator;
29+
2730
use function count;
2831

29-
class MountProvider implements IMountProvider {
32+
class MountProvider implements IMountProvider, IPartialMountProvider {
3033
/**
3134
* @param IConfig $config
3235
* @param IManager $shareManager
@@ -51,7 +54,7 @@ public function __construct(
5154
*/
5255
public function getMountsForUser(IUser $user, IStorageFactory $loader) {
5356
$userId = $user->getUID();
54-
$shares = array_merge(
57+
$shares = $this->mergeIterables(
5558
$this->shareManager->getSharedWith($userId, IShare::TYPE_USER, null, -1),
5659
$this->shareManager->getSharedWith($userId, IShare::TYPE_GROUP, null, -1),
5760
$this->shareManager->getSharedWith($userId, IShare::TYPE_CIRCLE, null, -1),
@@ -62,17 +65,24 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader) {
6265
$shares = $this->filterShares($shares, $userId);
6366
$superShares = $this->buildSuperShares($shares, $user);
6467

65-
return $this->getMountsFromSuperShares($userId, $superShares, $loader, $user);
68+
return array_values(
69+
$this->getMountsFromSuperShares(
70+
$userId,
71+
$superShares,
72+
$loader,
73+
$user,
74+
),
75+
);
6676
}
6777

6878
/**
6979
* Groups shares by path (nodeId) and target path
7080
*
71-
* @param IShare[] $shares
81+
* @param iterable<IShare> $shares
7282
* @return IShare[][] array of grouped shares, each element in the
7383
* array is a group which itself is an array of shares
7484
*/
75-
private function groupShares(array $shares) {
85+
private function groupShares(iterable $shares): array {
7686
$tmp = [];
7787

7888
foreach ($shares as $share) {
@@ -108,11 +118,11 @@ private function groupShares(array $shares) {
108118
* the shares in the group, forming the most permissive combination
109119
* possible.
110120
*
111-
* @param IShare[] $allShares
121+
* @param iterable<IShare> $allShares
112122
* @param IUser $user user
113123
* @return list<array{IShare, array<IShare>}> Tuple of [superShare, groupedShares]
114124
*/
115-
private function buildSuperShares(array $allShares, IUser $user) {
125+
private function buildSuperShares(iterable $allShares, IUser $user): array {
116126
$result = [];
117127

118128
$groupedShares = $this->groupShares($allShares);
@@ -237,8 +247,7 @@ private function adjustTarget(
237247
// null groups which usually appear with group backend
238248
// caching inconsistencies
239249
$this->logger->debug(
240-
'Could not adjust share target for share ' . $share->getId(
241-
) . ' to make it consistent: ' . $e->getMessage(),
250+
'Could not adjust share target for share ' . $share->getId() . ' to make it consistent: ' . $e->getMessage(),
242251
['app' => 'files_sharing']
243252
);
244253
}
@@ -248,7 +257,7 @@ private function adjustTarget(
248257
* @param array $superShares
249258
* @param IStorageFactory $loader
250259
* @param IUser $user
251-
* @return array
260+
* @return array IMountPoint indexed by mount point
252261
* @throws Exception
253262
*/
254263
private function getMountsFromSuperShares(
@@ -261,13 +270,11 @@ private function getMountsFromSuperShares(
261270
$mounts = [];
262271
$view = new View('/' . $userId . '/files');
263272
$ownerViews = [];
264-
$sharingDisabledForUser
265-
= $this->shareManager->sharingDisabledForUser($userId);
273+
$sharingDisabledForUser = $this->shareManager->sharingDisabledForUser($userId);
266274
/** @var CappedMemoryCache<bool> $folderExistCache */
267275
$foldersExistCache = new CappedMemoryCache();
268276

269-
$validShareCache
270-
= $this->cacheFactory->createLocal('share-valid-mountpoint-max');
277+
$validShareCache = $this->cacheFactory->createLocal('share-valid-mountpoint-max');
271278
$maxValidatedShare = $validShareCache->get($userId) ?? 0;
272279
$newMaxValidatedShare = $maxValidatedShare;
273280

@@ -312,12 +319,10 @@ private function getMountsFromSuperShares(
312319
$event = new ShareMountedEvent($mount);
313320
$this->eventDispatcher->dispatchTyped($event);
314321

315-
$mounts[$mount->getMountPoint()]
316-
= $allMounts[$mount->getMountPoint()] = $mount;
322+
$mounts[$mount->getMountPoint()] = $allMounts[$mount->getMountPoint()] = $mount;
317323
foreach ($event->getAdditionalMounts() as $additionalMount) {
318-
$allMounts[$additionalMount->getMountPoint()]
319-
= $mounts[$additionalMount->getMountPoint()]
320-
= $additionalMount;
324+
$mounts[$additionalMount->getMountPoint()] = $additionalMount;
325+
$allMounts[$additionalMount->getMountPoint()] = $additionalMount;
321326
}
322327
} catch (Exception $e) {
323328
$this->logger->error(
@@ -333,24 +338,74 @@ private function getMountsFromSuperShares(
333338
$validShareCache->set($userId, $newMaxValidatedShare, 24 * 60 * 60);
334339

335340
// array_filter removes the null values from the array
336-
return array_values(array_filter($mounts));
341+
return array_filter($mounts);
337342
}
338343

339344
/**
340345
* Filters out shares owned or shared by the user and ones for which the
341346
* user has no permissions.
342347
*
343-
* @param IShare[] $shares
344-
* @return IShare[]
348+
* @param iterable<IShare> $shares
349+
* @return iterable<IShare>
345350
*/
346-
private function filterShares(array $shares, string $userId): array {
347-
return array_filter(
348-
$shares,
349-
static function (IShare $share) use ($userId) {
350-
return $share->getPermissions() > 0
351-
&& $share->getShareOwner() !== $userId
352-
&& $share->getSharedBy() !== $userId;
351+
private function filterShares(iterable $shares, string $userId): iterable {
352+
foreach ($shares as $share) {
353+
if (
354+
$share->getPermissions() > 0
355+
&& $share->getShareOwner() !== $userId
356+
&& $share->getSharedBy() !== $userId
357+
) {
358+
yield $share;
353359
}
360+
}
361+
}
362+
363+
public function getMountsForPath(
364+
string $path,
365+
bool $forChildren,
366+
array $mountProviderArgs,
367+
IStorageFactory $loader,
368+
): array {
369+
$limit = -1;
370+
$user = $mountProviderArgs[0]->mountInfo->getUser();
371+
$userId = $user->getUID();
372+
373+
if (!$forChildren) {
374+
// override path with mount point when fetching without children
375+
$path = $mountProviderArgs[0]->mountInfo->getMountPoint();
376+
}
377+
378+
// remove /uid/files as the target is stored without
379+
$path = \substr($path, \strlen('/' . $userId . '/files'));
380+
// remove trailing slash
381+
$path = \rtrim($path, '/');
382+
383+
// make sure trailing slash is present when loading children
384+
if ($forChildren || $path === '') {
385+
$path .= '/';
386+
}
387+
388+
$shares = $this->mergeIterables(
389+
$this->shareManager->getSharedWithByPath($userId, IShare::TYPE_USER, $path, $forChildren, $limit),
390+
$this->shareManager->getSharedWithByPath($userId, IShare::TYPE_GROUP, $path, $forChildren, $limit),
391+
$this->shareManager->getSharedWithByPath($userId, IShare::TYPE_CIRCLE, $path, $forChildren, $limit),
392+
$this->shareManager->getSharedWithByPath($userId, IShare::TYPE_ROOM, $path, $forChildren, $limit),
393+
$this->shareManager->getSharedWithByPath($userId, IShare::TYPE_DECK, $path, $forChildren, $limit),
354394
);
395+
396+
$shares = $this->filterShares($shares, $userId);
397+
$superShares = $this->buildSuperShares($shares, $user);
398+
399+
return $this->getMountsFromSuperShares($userId, $superShares, $loader, $user);
400+
}
401+
402+
/**
403+
* @param iterable ...$iterables
404+
* @return iterable
405+
*/
406+
private function mergeIterables(...$iterables): iterable {
407+
foreach ($iterables as $iterable) {
408+
yield from $iterable;
409+
}
355410
}
356411
}

0 commit comments

Comments
 (0)