mirror of
https://github.com/nextcloud/server.git
synced 2026-02-19 02:38:40 -05:00
Merge pull request #52634 from nextcloud/perf/share20/get-all-shares-in-folder
This commit is contained in:
commit
648745d524
8 changed files with 121 additions and 59 deletions
|
|
@ -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'));
|
||||
|
|
|
|||
|
|
@ -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'));
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
24
lib/public/Share/IShareProviderSupportsAllSharesInFolder.php
Normal file
24
lib/public/Share/IShareProviderSupportsAllSharesInFolder.php
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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],
|
||||
|
|
|
|||
Loading…
Reference in a new issue