Skip to content

Commit 526dba0

Browse files
committed
feat(sharing): implement path-based mount provider changes in MountProviders
[skip ci] Signed-off-by: Salvatore Martire <[email protected]>
1 parent 7f26f7e commit 526dba0

File tree

8 files changed

+440
-3
lines changed

8 files changed

+440
-3
lines changed

apps/federatedfilesharing/lib/FederatedShareProvider.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,45 @@ public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
748748
return $shares;
749749
}
750750

751+
public function getSharedWithByNodeIds(
752+
$userId,
753+
$shareType,
754+
$nodeIds,
755+
$limit,
756+
$offset
757+
) {
758+
/** @var IShare[] $shares */
759+
$shares = [];
760+
761+
//Get shares directly with this user
762+
$qb = $this->dbConnection->getQueryBuilder();
763+
$qb->select('*')
764+
->from('share');
765+
766+
// Order by id
767+
$qb->orderBy('id');
768+
769+
// Set limit and offset
770+
if ($limit !== -1) {
771+
$qb->setMaxResults($limit);
772+
}
773+
$qb->setFirstResult($offset);
774+
775+
$qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY)));
776+
$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
777+
$qb->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($nodeIds, IQueryBuilder::PARAM_INT_ARRAY)));
778+
779+
$cursor = $qb->executeQuery();
780+
781+
while ($data = $cursor->fetch()) {
782+
$shares[] = $this->createShareObject($data);
783+
}
784+
$cursor->closeCursor();
785+
786+
787+
return $shares;
788+
}
789+
751790
/**
752791
* Get a share by token
753792
*

apps/files_sharing/lib/External/MountProvider.php

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,23 @@
77
*/
88
namespace OCA\Files_Sharing\External;
99

10+
use LogicException;
1011
use OCP\DB\QueryBuilder\IQueryBuilder;
1112
use OCP\Federation\ICloudIdManager;
1213
use OCP\Files\Config\IMountProvider;
14+
use OCP\Files\Config\IPartialMountProvider;
1315
use OCP\Files\Storage\IStorageFactory;
1416
use OCP\Http\Client\IClientService;
1517
use OCP\IDBConnection;
1618
use OCP\IUser;
1719
use OCP\Server;
1820
use OCP\Share\IShare;
21+
use function count;
22+
use function str_starts_with;
23+
use function strlen;
24+
use function substr;
1925

20-
class MountProvider implements IMountProvider {
26+
class MountProvider implements IMountProvider, IPartialMountProvider {
2127
public const STORAGE = '\OCA\Files_Sharing\External\Storage';
2228

2329
/**
@@ -66,4 +72,60 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader) {
6672
$result->closeCursor();
6773
return $mounts;
6874
}
75+
76+
public function getMountsFromMountPoints(
77+
string $path,
78+
array $mountProviderArgs,
79+
IStorageFactory $loader,
80+
): array {
81+
if (\empty($mountProviderArgs)) {
82+
return [];
83+
}
84+
85+
$uniqueMountOwnerIds = [];
86+
$user = null;
87+
foreach ($mountProviderArgs as $mountProviderArg) {
88+
$mountInfo = $mountProviderArg->mountInfo;
89+
// get a list of unique owner IDs root mount IDs
90+
$user ??= $mountInfo->getUser();
91+
$uniqueMountOwnerIds[$user->getUID()] ??= true;
92+
}
93+
$uniqueMountOwnerIds = array_keys($uniqueMountOwnerIds);
94+
95+
// make sure the MPs belong to the same user
96+
if ($user === null || count($uniqueMountOwnerIds) !== 1) {
97+
// question: what kind of exception to throw in here?
98+
throw new LogicException();
99+
}
100+
101+
$mountOwnerId = $user->getUID();
102+
$pathPrefix = "/$mountOwnerId/files";
103+
$pathHashes = [];
104+
foreach ($mountProviderArgs as $mountProviderArg) {
105+
$mountPoint =
106+
rtrim($mountProviderArg->mountInfo->getMountPoint(), '/');
107+
if (str_starts_with($mountPoint, $pathPrefix)) {
108+
$pathHashes[] = md5(substr($mountPoint, strlen($pathPrefix)));
109+
}
110+
}
111+
112+
$qb = $this->connection->getQueryBuilder();
113+
$qb->select('remote', 'share_token', 'password', 'mountpoint', 'owner')
114+
->from('share_external')
115+
->where($qb->expr()->eq('user', $qb->createNamedParameter($user->getUID())))
116+
->andWhere($qb->expr()->in('mountpoint_hash',
117+
$qb->createNamedParameter($pathHashes, IQueryBuilder::PARAM_STR_ARRAY)))
118+
->andWhere($qb->expr()->eq('accepted', $qb->createNamedParameter
119+
(IShare::STATUS_ACCEPTED, IQueryBuilder::PARAM_INT)));
120+
$result = $qb->executeQuery();
121+
$mounts = [];
122+
while ($row = $result->fetch()) {
123+
$row['manager'] = $this;
124+
$row['token'] = $row['share_token'];
125+
$mount = $this->getMount($user, $row, $loader);
126+
$mounts[$mount->getMountPoint()] = $mount;
127+
}
128+
$result->closeCursor();
129+
return $mounts;
130+
}
69131
}

apps/files_sharing/lib/MountProvider.php

Lines changed: 148 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,55 @@
99

1010
use Exception;
1111
use InvalidArgumentException;
12+
use LogicException;
1213
use OC\Files\View;
1314
use OCA\Files_Sharing\Event\ShareMountedEvent;
15+
use OCA\Talk\Share\RoomShareProvider;
1416
use OCP\Cache\CappedMemoryCache;
17+
use OCP\DB\QueryBuilder\IQueryBuilder;
1518
use OCP\EventDispatcher\IEventDispatcher;
1619
use OCP\Files\Config\IMountProvider;
20+
use OCP\Files\Config\IPartialMountProvider;
21+
use OCP\Files\IRootFolder;
1722
use OCP\Files\Mount\IMountManager;
1823
use OCP\Files\Mount\IMountPoint;
1924
use OCP\Files\Storage\IStorageFactory;
2025
use OCP\ICacheFactory;
2126
use OCP\IConfig;
27+
use OCP\IDBConnection;
2228
use OCP\IUser;
2329
use OCP\Share\IAttributes;
2430
use OCP\Share\IManager;
2531
use OCP\Share\IShare;
2632
use Psr\Log\LoggerInterface;
33+
use function array_filter;
34+
use function array_values;
2735
use function count;
2836

29-
class MountProvider implements IMountProvider {
37+
class MountProvider implements IMountProvider, IPartialMountProvider {
38+
39+
private const SUPPORTED_SHARE_TYPES = [
40+
IShare::TYPE_USER,
41+
IShare::TYPE_GROUP,
42+
IShare::TYPE_USERGROUP,
43+
RoomShareProvider::SHARE_TYPE_USERROOM,
44+
IShare::TYPE_CIRCLE,
45+
IShare::TYPE_ROOM,
46+
IShare::TYPE_DECK,
47+
IShare::TYPE_SCIENCEMESH,
48+
];
49+
50+
/**
51+
* Maps internal share types to the right provider
52+
*
53+
* NOTE: this information should come either from the provider or from
54+
* the provider factory!
55+
*/
56+
private const TYPE_MAPPING = [
57+
IShare::TYPE_USERGROUP => IShare::TYPE_GROUP,
58+
RoomShareProvider::SHARE_TYPE_USERROOM => IShare::TYPE_ROOM,
59+
];
60+
3061
/**
3162
* @param IConfig $config
3263
* @param IManager $shareManager
@@ -39,6 +70,8 @@ public function __construct(
3970
protected IEventDispatcher $eventDispatcher,
4071
protected ICacheFactory $cacheFactory,
4172
protected IMountManager $mountManager,
73+
protected IDBConnection $dbConn,
74+
protected IRootFolder $rootFolder,
4275
) {
4376
}
4477

@@ -244,6 +277,64 @@ public function adjustTarget(
244277
);
245278
}
246279
}
280+
281+
/**
282+
* @inheritdoc
283+
*/
284+
public function getMountsFromMountPoints(
285+
string $path,
286+
array $mountProviderArgs,
287+
IStorageFactory $loader,
288+
): array {
289+
if (empty($mountProviderArgs)) {
290+
return [];
291+
}
292+
293+
$uniqueMountOwnerIds = [];
294+
$uniqueRootIds = [];
295+
$user = null;
296+
foreach ($mountProviderArgs as $mountProviderArg) {
297+
$mountInfo = $mountProviderArg->mountInfo;
298+
// get a list of unique owner IDs root mount IDs
299+
$user ??= $mountInfo->getUser();
300+
$uniqueMountOwnerIds[$user->getUID()] ??= true;
301+
$uniqueRootIds[$mountInfo->getRootId()] ??= true;
302+
}
303+
$uniqueMountOwnerIds = array_keys($uniqueMountOwnerIds);
304+
$uniqueRootIds = array_keys($uniqueRootIds);
305+
306+
// make sure the MPs belong to the same user
307+
if ($user === null || count($uniqueMountOwnerIds) !== 1) {
308+
// question: what kind of exception to throw in here?
309+
throw new LogicException();
310+
}
311+
312+
$rootIdsByShareProviderType = $this->getShareInfo($user, $uniqueRootIds);
313+
$sharesInPath = [];
314+
foreach ($rootIdsByShareProviderType as $shareType => $rootIds) {
315+
// todo: pagination for many rootIds
316+
$sharesInPath[] = $this->shareManager->getSharedWithByNodes(
317+
$uniqueMountOwnerIds[0],
318+
$shareType,
319+
$rootIds,
320+
-1
321+
);
322+
}
323+
$sharesInPath = array_merge(...$sharesInPath);
324+
325+
// filter out shares owned or shared by the user and ones for which
326+
// the user has no permissions
327+
$shares = $this->filterShares($sharesInPath, $user->getUID());
328+
$superShares = $this->buildSuperShares($shares, $user);
329+
330+
return $this->getMountsFromSuperShares(
331+
$user->getUID(),
332+
$superShares,
333+
$loader,
334+
$user,
335+
);
336+
}
337+
247338
/**
248339
* @param string $userId
249340
* @param array $superShares
@@ -334,7 +425,7 @@ public function getMountsFromSuperShares(
334425
$validShareCache->set($userId, $newMaxValidatedShare, 24 * 60 * 60);
335426

336427
// array_filter removes the null values from the array
337-
return array_values(array_filter($mounts));
428+
return array_filter($mounts);
338429
}
339430

340431
/**
@@ -354,4 +445,59 @@ static function (IShare $share) use ($userId) {
354445
}
355446
);
356447
}
448+
449+
/**
450+
* Helper function to retrieve data needed to determine which
451+
* IShareProviders need to be queried: IShare::TYPE_*.
452+
*
453+
* @see IShare::TYPE_* constants
454+
*
455+
* @param int[] $uniqueRootIds
456+
* @return array<int, int[]> Array of the shared node IDs,
457+
* keyed by the share type.
458+
* @throws \OCP\DB\Exception
459+
*/
460+
public function getShareInfo(IUser $user, array $uniqueRootIds): array {
461+
$mountOwnerId = $user->getUID();
462+
// retrieve the share type for the received files
463+
$qb = $this->dbConn->getQueryBuilder();
464+
$qb->select('file_source', 'share_type')
465+
->from('share')
466+
->where(
467+
$qb->expr()->in(
468+
'file_source',
469+
$qb->createNamedParameter(
470+
$uniqueRootIds,
471+
IQueryBuilder::PARAM_STR_ARRAY
472+
)
473+
)
474+
)
475+
->andWhere(
476+
$qb->expr()->in(
477+
'share_type',
478+
$qb->createNamedParameter(
479+
self::SUPPORTED_SHARE_TYPES,
480+
IQueryBuilder::PARAM_INT_ARRAY
481+
)
482+
)
483+
)
484+
->andWhere(
485+
$qb->expr()->eq(
486+
'share_with',
487+
$qb->createNamedParameter($mountOwnerId)
488+
)
489+
)
490+
->groupBy('file_source', 'share_type');
491+
$cursor = $qb->executeQuery();
492+
493+
// group IDs of the roots of the mountpoints by type
494+
$rootIdsByType = [];
495+
while ($row = $cursor->fetch()) {
496+
$mappedType = self::TYPE_MAPPING[$row['share_type']] ?? $row['share_type'];
497+
$rootIdsByType[$mappedType][] = $row['file_source'];
498+
}
499+
$cursor->closeCursor();
500+
501+
return $rootIdsByType;
502+
}
357503
}

apps/sharebymail/lib/ShareByMailProvider.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,39 @@ public function getSharedWith($userId, $shareType, $node, $limit, $offset): arra
944944
return $shares;
945945
}
946946

947+
public function getSharedWithByNodeIds($userId, $shareType, $nodeIds, $limit, $offset): array {
948+
/** @var IShare[] $shares */
949+
$shares = [];
950+
951+
//Get shares directly with this user
952+
$qb = $this->dbConnection->getQueryBuilder();
953+
$qb->select('*')
954+
->from('share');
955+
956+
// Order by id
957+
$qb->orderBy('id');
958+
959+
// Set limit and offset
960+
if ($limit !== -1) {
961+
$qb->setMaxResults($limit);
962+
}
963+
$qb->setFirstResult($offset);
964+
965+
$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)));
966+
$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)));
967+
$qb->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter ($nodeIds, IQueryBuilder::PARAM_INT_ARRAY)));
968+
969+
$cursor = $qb->executeQuery();
970+
971+
while ($data = $cursor->fetch()) {
972+
$shares[] = $this->createShareObject($data);
973+
}
974+
$cursor->closeCursor();
975+
976+
977+
return $shares;
978+
}
979+
947980
/**
948981
* Get a share by token
949982
*

0 commit comments

Comments
 (0)