diff options
-rw-r--r-- | apps/federatedfilesharing/lib/FederatedShareProvider.php | 39 | ||||
-rw-r--r-- | apps/sharebymail/lib/ShareByMailProvider.php | 37 | ||||
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 1 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 1 | ||||
-rw-r--r-- | lib/private/Share20/DefaultShareProvider.php | 42 | ||||
-rw-r--r-- | lib/private/Share20/Manager.php | 13 | ||||
-rw-r--r-- | lib/public/Share/IShareProviderSupportsAllSharesInFolder.php | 24 | ||||
-rw-r--r-- | tests/lib/Share20/ManagerTest.php | 23 |
8 files changed, 121 insertions, 59 deletions
diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php index d993b35845c..7c95b83a5dd 100644 --- a/apps/federatedfilesharing/lib/FederatedShareProvider.php +++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php @@ -26,6 +26,7 @@ use OCP\Share\Exceptions\GenericShareException; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IShare; use OCP\Share\IShareProvider; +use OCP\Share\IShareProviderSupportsAllSharesInFolder; use Psr\Log\LoggerInterface; /** @@ -33,7 +34,7 @@ use Psr\Log\LoggerInterface; * * @package OCA\FederatedFileSharing */ -class FederatedShareProvider implements IShareProvider { +class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAllSharesInFolder { public const SHARE_TYPE_REMOTE = 6; /** @var string */ @@ -553,7 +554,17 @@ class FederatedShareProvider implements IShareProvider { if (!$shallow) { throw new \Exception('non-shallow getSharesInFolder is no longer supported'); } + return $this->getSharesInFolderInternal($userId, $node, $reshares); + } + + public function getAllSharesInFolder(Folder $node): array { + return $this->getSharesInFolderInternal(null, $node, null); + } + /** + * @return array<int, list<IShare>> + */ + private function getSharesInFolderInternal(?string $userId, Folder $node, ?bool $reshares): array { $qb = $this->dbConnection->getQueryBuilder(); $qb->select('*') ->from('share', 's') @@ -562,18 +573,20 @@ class FederatedShareProvider implements IShareProvider { $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_REMOTE)) ); - /** - * Reshares for this user are shares where they are the owner. - */ - if ($reshares === false) { - $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); - } else { - $qb->andWhere( - $qb->expr()->orX( - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) - ) - ); + if ($userId !== null) { + /** + * Reshares for this user are shares where they are the owner. + */ + if ($reshares !== true) { + $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); + } else { + $qb->andWhere( + $qb->expr()->orX( + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) + ) + ); + } } $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid')); diff --git a/apps/sharebymail/lib/ShareByMailProvider.php b/apps/sharebymail/lib/ShareByMailProvider.php index e6e1cf509e9..194a402848e 100644 --- a/apps/sharebymail/lib/ShareByMailProvider.php +++ b/apps/sharebymail/lib/ShareByMailProvider.php @@ -1112,6 +1112,17 @@ class ShareByMailProvider extends DefaultShareProvider implements IShareProvider } public function getSharesInFolder($userId, Folder $node, $reshares, $shallow = true): array { + return $this->getSharesInFolderInternal($userId, $node, $reshares); + } + + public function getAllSharesInFolder(Folder $node): array { + return $this->getSharesInFolderInternal(null, $node, null); + } + + /** + * @return array<int, list<IShare>> + */ + private function getSharesInFolderInternal(?string $userId, Folder $node, ?bool $reshares): array { $qb = $this->dbConnection->getQueryBuilder(); $qb->select('*') ->from('share', 's') @@ -1120,18 +1131,20 @@ class ShareByMailProvider extends DefaultShareProvider implements IShareProvider $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_EMAIL)) ); - /** - * Reshares for this user are shares where they are the owner. - */ - if ($reshares === false) { - $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); - } else { - $qb->andWhere( - $qb->expr()->orX( - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) - ) - ); + if ($userId !== null) { + /** + * Reshares for this user are shares where they are the owner. + */ + if ($reshares !== true) { + $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); + } else { + $qb->andWhere( + $qb->expr()->orX( + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) + ) + ); + } } $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid')); diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 177abfefe8e..b1c6c453b0a 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -780,6 +780,7 @@ return array( 'OCP\\Share\\IShareHelper' => $baseDir . '/lib/public/Share/IShareHelper.php', 'OCP\\Share\\IShareProvider' => $baseDir . '/lib/public/Share/IShareProvider.php', 'OCP\\Share\\IShareProviderSupportsAccept' => $baseDir . '/lib/public/Share/IShareProviderSupportsAccept.php', + 'OCP\\Share\\IShareProviderSupportsAllSharesInFolder' => $baseDir . '/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php', 'OCP\\Share\\IShareProviderWithNotification' => $baseDir . '/lib/public/Share/IShareProviderWithNotification.php', 'OCP\\Share_Backend' => $baseDir . '/lib/public/Share_Backend.php', 'OCP\\Share_Backend_Collection' => $baseDir . '/lib/public/Share_Backend_Collection.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index ddccd0692ca..6eecb2da4b5 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -821,6 +821,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Share\\IShareHelper' => __DIR__ . '/../../..' . '/lib/public/Share/IShareHelper.php', 'OCP\\Share\\IShareProvider' => __DIR__ . '/../../..' . '/lib/public/Share/IShareProvider.php', 'OCP\\Share\\IShareProviderSupportsAccept' => __DIR__ . '/../../..' . '/lib/public/Share/IShareProviderSupportsAccept.php', + 'OCP\\Share\\IShareProviderSupportsAllSharesInFolder' => __DIR__ . '/../../..' . '/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php', 'OCP\\Share\\IShareProviderWithNotification' => __DIR__ . '/../../..' . '/lib/public/Share/IShareProviderWithNotification.php', 'OCP\\Share_Backend' => __DIR__ . '/../../..' . '/lib/public/Share_Backend.php', 'OCP\\Share_Backend_Collection' => __DIR__ . '/../../..' . '/lib/public/Share_Backend_Collection.php', diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index a257bc4f7b5..e1eebe1e450 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -5,6 +5,7 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ + namespace OC\Share20; use OC\Files\Cache\Cache; @@ -31,6 +32,7 @@ use OCP\Share\IAttributes; use OCP\Share\IManager; use OCP\Share\IShare; use OCP\Share\IShareProviderSupportsAccept; +use OCP\Share\IShareProviderSupportsAllSharesInFolder; use OCP\Share\IShareProviderWithNotification; use Psr\Log\LoggerInterface; use function str_starts_with; @@ -40,7 +42,7 @@ use function str_starts_with; * * @package OC\Share20 */ -class DefaultShareProvider implements IShareProviderWithNotification, IShareProviderSupportsAccept { +class DefaultShareProvider implements IShareProviderWithNotification, IShareProviderSupportsAccept, IShareProviderSupportsAllSharesInFolder { // Special share type for user modified group shares public const SHARE_TYPE_USERGROUP = 2; @@ -603,6 +605,17 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv throw new \Exception('non-shallow getSharesInFolder is no longer supported'); } + return $this->getSharesInFolderInternal($userId, $node, $reshares); + } + + public function getAllSharesInFolder(Folder $node): array { + return $this->getSharesInFolderInternal(null, $node, null); + } + + /** + * @return array<int, list<IShare>> + */ + private function getSharesInFolderInternal(?string $userId, Folder $node, ?bool $reshares): array { $qb = $this->dbConn->getQueryBuilder(); $qb->select('s.*', 'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash', @@ -613,18 +626,20 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv $qb->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter([IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK], IQueryBuilder::PARAM_INT_ARRAY))); - /** - * Reshares for this user are shares where they are the owner. - */ - if ($reshares === false) { - $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); - } else { - $qb->andWhere( - $qb->expr()->orX( - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) - ) - ); + if ($userId !== null) { + /** + * Reshares for this user are shares where they are the owner. + */ + if ($reshares !== true) { + $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); + } else { + $qb->andWhere( + $qb->expr()->orX( + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) + ) + ); + } } // todo? maybe get these from the oc_mounts table @@ -656,7 +671,6 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv foreach ($chunks as $chunk) { $qb->setParameter('chunk', $chunk, IQueryBuilder::PARAM_INT_ARRAY); - $a = $qb->getSQL(); $cursor = $qb->executeQuery(); while ($data = $cursor->fetch()) { $shares[$data['fileid']][] = $this->createShare($data); diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 3b247475afa..2104c07593a 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -51,6 +51,7 @@ use OCP\Share\IProviderFactory; use OCP\Share\IShare; use OCP\Share\IShareProvider; use OCP\Share\IShareProviderSupportsAccept; +use OCP\Share\IShareProviderSupportsAllSharesInFolder; use OCP\Share\IShareProviderWithNotification; use Psr\Log\LoggerInterface; @@ -1213,11 +1214,13 @@ class Manager implements IManager { $shares = []; foreach ($providers as $provider) { if ($isOwnerless) { - foreach ($node->getDirectoryListing() as $childNode) { - $data = $provider->getSharesByPath($childNode); - $fid = $childNode->getId(); - $shares[$fid] ??= []; - $shares[$fid] = array_merge($shares[$fid], $data); + // If the provider does not implement the additional interface, + // we lack a performant way of querying all shares and therefore ignore the provider. + if ($provider instanceof IShareProviderSupportsAllSharesInFolder) { + foreach ($provider->getAllSharesInFolder($node) as $fid => $data) { + $shares[$fid] ??= []; + $shares[$fid] = array_merge($shares[$fid], $data); + } } } else { foreach ($provider->getSharesInFolder($userId, $node, $reshares) as $fid => $data) { diff --git a/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php b/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php new file mode 100644 index 00000000000..e27da7682ce --- /dev/null +++ b/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php @@ -0,0 +1,24 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCP\Share; + +use OCP\Files\Folder; + +/** + * Allows defining a IShareProvider with support for the getAllSharesInFolder method. + * + * @since 32.0.0 + */ +interface IShareProviderSupportsAllSharesInFolder extends IShareProvider { + /** + * Get all shares in a folder. + * + * @return array<int, list<IShare>> + * @since 32.0.0 + */ + public function getAllSharesInFolder(Folder $node): array; +} diff --git a/tests/lib/Share20/ManagerTest.php b/tests/lib/Share20/ManagerTest.php index 9e778207a8e..357ae9ee678 100644 --- a/tests/lib/Share20/ManagerTest.php +++ b/tests/lib/Share20/ManagerTest.php @@ -55,6 +55,7 @@ use OCP\Share\IManager; use OCP\Share\IProviderFactory; use OCP\Share\IShare; use OCP\Share\IShareProvider; +use OCP\Share\IShareProviderSupportsAllSharesInFolder; use PHPUnit\Framework\MockObject\MockBuilder; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\LoggerInterface; @@ -4551,7 +4552,7 @@ class ManagerTest extends \Test\TestCase { $manager = $this->createManager($factory); $factory->setProvider($this->defaultProvider); - $extraProvider = $this->createMock(IShareProvider::class); + $extraProvider = $this->createMock(IShareProviderSupportsAllSharesInFolder::class); $factory->setSecondProvider($extraProvider); $share1 = $this->createMock(IShare::class); @@ -4559,28 +4560,20 @@ class ManagerTest extends \Test\TestCase { $mount = $this->createMock(IShareOwnerlessMount::class); - $file = $this->createMock(File::class); - $file - ->method('getId') - ->willReturn(1); - $folder = $this->createMock(Folder::class); $folder ->method('getMountPoint') ->willReturn($mount); - $folder - ->method('getDirectoryListing') - ->willReturn([$file]); $this->defaultProvider - ->method('getSharesByPath') - ->with($file) - ->willReturn([$share1]); + ->method('getAllSharesInFolder') + ->with($folder) + ->willReturn([1 => [$share1]]); $extraProvider - ->method('getSharesByPath') - ->with($file) - ->willReturn([$share2]); + ->method('getAllSharesInFolder') + ->with($folder) + ->willReturn([1 => [$share2]]); $this->assertSame([ 1 => [$share1, $share2], |