Skip to content
Draft
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
2 changes: 2 additions & 0 deletions apps/files_sharing/tests/CapabilitiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IDateTimeZone;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IURLGenerator;
use OCP\IUserManager;
Expand Down Expand Up @@ -80,6 +81,7 @@ private function getResults(array $map, bool $federationEnabled = true) {
$this->createMock(ShareDisableChecker::class),
$this->createMock(IDateTimeZone::class),
$this->createMock(IAppConfig::class),
$this->createMock(IDBConnection::class),
);
$cap = new Capabilities($config, $shareManager, $appManager);
$result = $this->getFilesSharingPart($cap->getCapabilities());
Expand Down
4 changes: 3 additions & 1 deletion apps/settings/tests/Settings/Admin/SharingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
use OCP\IConfig;
use OCP\IL10N;
use OCP\IURLGenerator;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;

#[Group(name: 'DB')]
class SharingTest extends TestCase {
/** @var Sharing */
private $admin;
Expand Down Expand Up @@ -104,7 +106,7 @@ public function testGetFormWithoutExcludedGroups(): void {
->willReturnCallback(function (string $key) use (&$initialStateCalls) {
$initialStateCalls[$key] = func_get_args();
});

$expectedInitialStateCalls = [
'sharingAppEnabled' => false,
'sharingDocumentation' => '',
Expand Down
2 changes: 1 addition & 1 deletion lib/private/Share20/DefaultShareProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,7 @@ public function getShareByToken($token) {
* @return \OCP\Share\IShare
* @throws InvalidShare
*/
private function createShare($data) {
private function createShare($data): IShare {
$share = new Share($this->rootFolder, $this->userManager);
$share->setId((int)$data['id'])
->setShareType((int)$data['share_type'])
Expand Down
92 changes: 68 additions & 24 deletions lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use OC\Share20\Exception\ProviderException;
use OCA\Files_Sharing\AppInfo\Application;
use OCA\Files_Sharing\SharedStorage;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\File;
use OCP\Files\Folder;
Expand All @@ -24,6 +25,7 @@
use OCP\IAppConfig;
use OCP\IConfig;
use OCP\IDateTimeZone;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\IURLGenerator;
Expand Down Expand Up @@ -83,6 +85,7 @@ public function __construct(
private ShareDisableChecker $shareDisableChecker,
private IDateTimeZone $dateTimeZone,
private IAppConfig $appConfig,
private IDBConnection $connection,
) {
$this->l = $this->l10nFactory->get('lib');
// The constructor of LegacyHooks registers the listeners of share events
Expand Down Expand Up @@ -1068,35 +1071,76 @@ protected function promoteReshares(IShare $share): void {
IShare::TYPE_EMAIL,
];

foreach ($userIds as $userId) {
foreach ($shareTypes as $shareType) {
// Figure out which users has some shares with which providers
$qb = $this->connection->getQueryBuilder();
$qb->select('uid_initiator', 'share_type', 'uid_owner', 'file_source')
->from('share')
->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY)))
->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($shareTypes, IQueryBuilder::PARAM_INT_ARRAY)))
->andWhere(
$qb->expr()->orX(
$qb->expr()->in('uid_initiator', $qb->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)),
// Special case for old shares created via the web UI
$qb->expr()->andX(
$qb->expr()->in('uid_owner', $qb->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)),
$qb->expr()->isNull('uid_initiator')
)
)
);

if (!$node instanceof Folder) {
$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId(), IQueryBuilder::PARAM_INT)));
}

$qb->orderBy('id');

$cursor = $qb->executeQuery();
/** @var array<string, list<array{IShare::TYPE_*, Node}>> $rawShare */
$rawShares = [];
while ($data = $cursor->fetch()) {
if (!isset($rawShares[$data['uid_initiator']])) {
$rawShares[$data['uid_initiator']] = [];
}
if (!in_array($data['share_type'], $rawShares[$data['uid_initiator']], true)) {
if ($node instanceof Folder) {
if ($data['file_source'] === null || $data['uid_owner'] === null) {
/* Ignore share of non-existing node */
continue;
}

// for federated shares the owner can be a remote user, in this
// case we use the initiator
if ($this->userManager->userExists($data['uid_owner'])) {
$userFolder = $this->rootFolder->getUserFolder($data['uid_owner']);
} else {
$userFolder = $this->rootFolder->getUserFolder($data['uid_initiator']);
}
$sharedNode = $userFolder->getFirstNodeById((int)$data['file_source']);
if (!$sharedNode) {
continue;
}
if ($node->getRelativePath($sharedNode->getPath()) !== null) {
$rawShares[$data['uid_initiator']][] = [(int)$data['share_type'], $sharedNode];
}
} elseif ($node instanceof File) {
$rawShares[$data['uid_initiator']][] = [(int)$data['share_type'], $node];
}
}
}
$cursor->closeCursor();

foreach ($rawShares as $userId => $shareInfos) {
foreach ($shareInfos as $shareInfo) {
[$shareType, $sharedNode] = $shareInfo;
try {
$provider = $this->factory->getProviderForType($shareType);
} catch (ProviderException $e) {
} catch (ProviderException) {
continue;
}

if ($node instanceof Folder) {
/* We need to get all shares by this user to get subshares */
$shares = $provider->getSharesBy($userId, $shareType, null, false, -1, 0);

foreach ($shares as $share) {
try {
$path = $share->getNode()->getPath();
} catch (NotFoundException) {
/* Ignore share of non-existing node */
continue;
}
if ($node->getRelativePath($path) !== null) {
/* If relative path is not null it means the shared node is the same or in a subfolder */
$reshareRecords[] = $share;
}
}
} else {
$shares = $provider->getSharesBy($userId, $shareType, $node, false, -1, 0);
foreach ($shares as $child) {
$reshareRecords[] = $child;
}
$shares = $provider->getSharesBy($userId, $shareType, $sharedNode, false, -1, 0);
foreach ($shares as $child) {
$reshareRecords[] = $child;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/.phpunit.cache/test-results

Large diffs are not rendered by default.

14 changes: 5 additions & 9 deletions tests/lib/Share20/LegacyHooksTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
namespace Test\Share20;

use OC\Share20\LegacyHooks;
use OC\Share20\Manager;
use OCP\Constants;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Cache\ICacheEntry;
Expand All @@ -20,18 +19,15 @@
use OCP\Share\Events\ShareDeletedFromSelfEvent;
use OCP\Share\IManager as IShareManager;
use OCP\Share\IShare;
use PHPUnit\Framework\Attributes\Group;
use Psr\Log\LoggerInterface;
use Test\TestCase;

#[Group(name: 'DB')]
class LegacyHooksTest extends TestCase {
/** @var LegacyHooks */
private $hooks;

/** @var IEventDispatcher */
private $eventDispatcher;

/** @var Manager */
private $manager;
private LegacyHooks $hooks;
private IEventDispatcher $eventDispatcher;
private IShareManager $manager;

protected function setUp(): void {
parent::setUp();
Expand Down
Loading
Loading