From 0fa64e743c8d738753e155c7e54e1906f25430d6 Mon Sep 17 00:00:00 2001 From: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Date: Tue, 30 Dec 2025 12:12:52 +0100 Subject: [PATCH 1/3] feature: implement IPartialShareProvider support Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Signed-off-by: Louis Chmn --- lib/Db/CoreQueryBuilder.php | 19 ++++++++++++- lib/Db/ShareWrapperRequest.php | 34 ++++++++++++++++++++++++ lib/Service/ShareWrapperService.php | 35 ++++++++++++++++++++++++ lib/ShareByCircleProvider.php | 41 ++++++++++++++++++++++++++++- 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/lib/Db/CoreQueryBuilder.php b/lib/Db/CoreQueryBuilder.php index 62e1d4c5d..4b7d15f4d 100644 --- a/lib/Db/CoreQueryBuilder.php +++ b/lib/Db/CoreQueryBuilder.php @@ -345,6 +345,20 @@ public function limitToFileSource(int $nodeId): void { $this->limitInt('file_source', $nodeId); } + public function limitToFileTarget(string $target, string $alias): void { + $this->orWhere( + $this->exprLimit('file_target', $target), + $this->exprLimit('file_target', $target, $alias), + ); + } + + public function limitToFileTargetLike(string $target, string $alias): void { + $this->orWhere( + $this->exprLike('file_target', $target), + $this->exprLike('file_target', $target, $alias), + ); + } + /** * @param array $files */ @@ -1465,9 +1479,11 @@ public function leftJoinFileCache(string $aliasShare) { * @param string $aliasShare * @param string $aliasShareMemberships * + * @return string the alias generated for the join + * * @throws RequestBuilderException */ - public function leftJoinShareChild(string $aliasShare, string $aliasShareMemberships = '') { + public function leftJoinShareChild(string $aliasShare, string $aliasShareMemberships = ''): string { $expr = $this->expr(); $aliasShareChild = $this->generateAlias($aliasShare, self::SHARE); @@ -1491,6 +1507,7 @@ public function leftJoinShareChild(string $aliasShare, string $aliasShareMembers ); // $this->selectAlias($aliasShareParent . '.permissions', 'parent_perms'); + return $aliasShareChild; } diff --git a/lib/Db/ShareWrapperRequest.php b/lib/Db/ShareWrapperRequest.php index bf84291ea..fe292aa61 100644 --- a/lib/Db/ShareWrapperRequest.php +++ b/lib/Db/ShareWrapperRequest.php @@ -359,6 +359,40 @@ public function getSharedWith( return $this->getItemsFromRequest($qb); } + public function getSharedWithByPath( + FederatedUser $federatedUser, + string $path, + bool $forChildren, + CircleProbe $probe, + ): array { + $qb = $this->getShareSelectSql(); + $qb->setOptions( + [CoreQueryBuilder::SHARE], + array_merge( + $probe->getAsOptions(), + ['getData' => true] + ) + ); + + $qb->leftJoinCircle(CoreQueryBuilder::SHARE, null, 'share_with'); + + $aliasCircle = $qb->generateAlias(CoreQueryBuilder::SHARE, CoreQueryBuilder::CIRCLE); + $qb->limitToFederatedUserMemberships(CoreQueryBuilder::SHARE, $aliasCircle, $federatedUser); + + $qb->leftJoinFileCache(CoreQueryBuilder::SHARE); + $qb->limitNull('parent', false); + $childAlias = $qb->leftJoinShareChild(CoreQueryBuilder::SHARE); + + if ($forChildren) { + $qb->limitToFileTargetLike($path . '_%', $childAlias); + } else { + $qb->limitToFileTarget($path, $childAlias); + } + + $qb->chunk($probe->getItemsOffset(), $probe->getItemsLimit()); + + return $this->getItemsFromRequest($qb); + } /** * @param FederatedUser $federatedUser diff --git a/lib/Service/ShareWrapperService.php b/lib/Service/ShareWrapperService.php index edecd09f2..90a710584 100644 --- a/lib/Service/ShareWrapperService.php +++ b/lib/Service/ShareWrapperService.php @@ -239,6 +239,29 @@ public function getSharedWith( return $shares; } + public function getSharedWithByPath( + FederatedUser $federatedUser, + string $path, + bool $forChildren, + ?CircleProbe $probe, + ): array { + $key = $this->generateSharedWithByPathCacheKey($federatedUser, $path, $forChildren, $probe?->getChecksum()); + + $cachedData = $this->cache->get($key); + try { + if (!is_string($cachedData)) { + throw new InvalidItemException(); + } + + return $this->deserializeList($cachedData, ShareWrapper::class); + } catch (InvalidItemException $e) { + } + + $shares = $this->shareWrapperRequest->getSharedWithByPath($federatedUser, $path, $forChildren, $probe); + $this->cache->set($key, json_encode($shares), self::CACHE_SHARED_WITH_TTL); + + return $shares; + } /** * @param FederatedUser $federatedUser @@ -322,6 +345,18 @@ private function createChild(IShare $share, FederatedUser $federatedUser): Share return $this->getShareById($childId, $federatedUser); } + private function generateSharedWithByPathCacheKey( + FederatedUser $federatedUser, + string $path, + bool $forChildren, + ?string $probeSum, + ): string { + $pathHash = \md5($path); + return $federatedUser->getSingleId() . '#' + . $pathHash . '#' + . $forChildren . '#' + . $probeSum; + } /** * @param FederatedUser $federatedUser diff --git a/lib/ShareByCircleProvider.php b/lib/ShareByCircleProvider.php index 847711cff..7b8501ce2 100644 --- a/lib/ShareByCircleProvider.php +++ b/lib/ShareByCircleProvider.php @@ -56,6 +56,7 @@ use OCP\Share\Exceptions\AlreadySharedException; use OCP\Share\Exceptions\IllegalIDChangeException; use OCP\Share\Exceptions\ShareNotFound; +use OCP\Share\IPartialShareProvider; use OCP\Share\IShare; use OCP\Share\IShareProvider; use Psr\Log\LoggerInterface; @@ -65,7 +66,7 @@ * * @package OCA\Circles */ -class ShareByCircleProvider implements IShareProvider { +class ShareByCircleProvider implements IShareProvider, IPartialShareProvider { use TArrayTools; use TStringTools; use TNCLogger; @@ -522,6 +523,44 @@ function (ShareWrapper $wrapper) { ); } + public function getSharedWithByPath( + string $userId, + int $shareType, + string $path, + bool $forChildren, + int $limit, + int $offset, + ): iterable { + if ($shareType !== IShare::TYPE_CIRCLE) { + return []; + } + + $federatedUser = $this->federatedUserService->getLocalFederatedUser($userId); + $probe = new CircleProbe(); + $probe->includePersonalCircles() + ->includeSystemCircles() + ->mustBeMember() + ->setItemsLimit($limit) + ->setItemsOffset($offset); + + $wrappedShares = $this->shareWrapperService->getSharedWithByPath( + $federatedUser, + $path, + $forChildren, + $probe, + ); + + /** @var array */ + return array_filter( + array_map( + function (ShareWrapper $wrapper) { + return $wrapper->getShare( + $this->rootFolder, $this->userManager, $this->urlGenerator, true + ); + }, $wrappedShares + ) + ); + } /** * @param string $token From 23174efacbb94a6864bd600b51b30fd2be27ae66 Mon Sep 17 00:00:00 2001 From: Louis Chmn Date: Thu, 8 Jan 2026 11:54:11 +0100 Subject: [PATCH 2/3] chore: Bump nextcloud/ocp Signed-off-by: Louis Chmn --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index b3bfa7125..ffdc4a97f 100644 --- a/composer.lock +++ b/composer.lock @@ -70,12 +70,12 @@ "source": { "type": "git", "url": "https://github.com/nextcloud-deps/ocp.git", - "reference": "2f3e07f61634b2d9bb6d8572e39614971798681a" + "reference": "ffd97f8e6969488ab12894546f1a93231ffbf7c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/2f3e07f61634b2d9bb6d8572e39614971798681a", - "reference": "2f3e07f61634b2d9bb6d8572e39614971798681a", + "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/ffd97f8e6969488ab12894546f1a93231ffbf7c2", + "reference": "ffd97f8e6969488ab12894546f1a93231ffbf7c2", "shasum": "" }, "require": { @@ -111,7 +111,7 @@ "issues": "https://github.com/nextcloud-deps/ocp/issues", "source": "https://github.com/nextcloud-deps/ocp/tree/master" }, - "time": "2026-01-01T01:02:28+00:00" + "time": "2026-01-07T16:18:20+00:00" }, { "name": "psr/clock", From 7b54110ec71397c4e49399513daac0f3e3c99052 Mon Sep 17 00:00:00 2001 From: Louis Chmn Date: Thu, 8 Jan 2026 12:13:35 +0100 Subject: [PATCH 3/3] fix(test): Psalm errors Signed-off-by: Louis Chmn --- tests/psalm-baseline.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index 1bd0313d5..3b78e1f8a 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -374,9 +374,6 @@ - - - @@ -386,6 +383,7 @@ + getShare($this->rootFolder, $this->userManager, $this->urlGenerator)]]>