Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions apps/federatedfilesharing/lib/FederatedShareProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
use OCP\Share\IShareProviderSupportsAllSharesInFolder;
use Psr\Log\LoggerInterface;

/**
* Class FederatedShareProvider
*
* @package OCA\FederatedFileSharing
*/
class FederatedShareProvider implements IShareProvider {
class FederatedShareProvider implements IShareProvider, IShareProviderSupportsAllSharesInFolder {
public const SHARE_TYPE_REMOTE = 6;

/** @var string */
Expand Down Expand Up @@ -553,7 +554,17 @@ public function getSharesInFolder($userId, Folder $node, $reshares, $shallow = t
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')
Expand All @@ -562,18 +573,20 @@ public function getSharesInFolder($userId, Folder $node, $reshares, $shallow = t
$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'));
Expand Down
37 changes: 25 additions & 12 deletions apps/sharebymail/lib/ShareByMailProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,17 @@ protected function getRawShare(int $id): array {
}

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')
Expand All @@ -1120,18 +1131,20 @@ public function getSharesInFolder($userId, Folder $node, $reshares, $shallow = t
$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'));
Expand Down
1 change: 1 addition & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,7 @@
'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',
Expand Down
1 change: 1 addition & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,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',
Expand Down
42 changes: 28 additions & 14 deletions lib/private/Share20/DefaultShareProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/

namespace OC\Share20;

use OC\Files\Cache\Cache;
Expand All @@ -31,6 +32,7 @@
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;
Expand All @@ -40,7 +42,7 @@
*
* @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;

Expand Down Expand Up @@ -603,6 +605,17 @@ public function getSharesInFolder($userId, Folder $node, $reshares, $shallow = t
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',
Expand All @@ -613,18 +626,20 @@ public function getSharesInFolder($userId, Folder $node, $reshares, $shallow = t

$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
Expand Down Expand Up @@ -656,7 +671,6 @@ public function getSharesInFolder($userId, Folder $node, $reshares, $shallow = t

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);
Expand Down
13 changes: 8 additions & 5 deletions lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
use OCP\Share\IShareProviderSupportsAccept;
use OCP\Share\IShareProviderSupportsAllSharesInFolder;
use OCP\Share\IShareProviderWithNotification;
use Psr\Log\LoggerInterface;

Expand Down Expand Up @@ -1213,11 +1214,13 @@ public function getSharesInFolder($userId, Folder $node, $reshares = false, $sha
$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) {
Expand Down
24 changes: 24 additions & 0 deletions lib/public/Share/IShareProviderSupportsAllSharesInFolder.php
Original file line number Diff line number Diff line change
@@ -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 31.0.6
*/
interface IShareProviderSupportsAllSharesInFolder extends IShareProvider {
/**
* Get all shares in a folder.
*
* @return array<int, list<IShare>>
* @since 31.0.6
*/
public function getAllSharesInFolder(Folder $node): array;
}
23 changes: 8 additions & 15 deletions tests/lib/Share20/ManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
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;
Expand Down Expand Up @@ -4552,36 +4553,28 @@ public function testGetSharesInFolderOwnerless(): void {
$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);
$share2 = $this->createMock(IShare::class);

$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],
Expand Down
Loading