diff --git a/lib/Db/CircleRequest.php b/lib/Db/CircleRequest.php index 5ca38fc16..1f694ce5d 100644 --- a/lib/Db/CircleRequest.php +++ b/lib/Db/CircleRequest.php @@ -300,7 +300,7 @@ public function getFederatedUserBySingleId(string $singleId): FederatedUser { * @throws RequestBuilderException */ public function getSingleCircle(IFederatedUser $initiator): Circle { - $qb = $this->getCircleSelectSql(CoreQueryBuilder::SINGLE); + $qb = $this->getCircleSelectSql(CoreQueryBuilder::SINGLE, true); if ($initiator instanceof FederatedUser) { $member = new Member(); diff --git a/lib/Db/CircleRequestBuilder.php b/lib/Db/CircleRequestBuilder.php index d0cb5f588..1f707a21a 100644 --- a/lib/Db/CircleRequestBuilder.php +++ b/lib/Db/CircleRequestBuilder.php @@ -68,14 +68,21 @@ protected function getCircleUpdateSql(): CoreQueryBuilder { /** * @param string $alias + * @param bool $single * * @return CoreQueryBuilder */ - protected function getCircleSelectSql(string $alias = CoreQueryBuilder::CIRCLE): CoreQueryBuilder { + protected function getCircleSelectSql( + string $alias = CoreQueryBuilder::CIRCLE, + bool $single = false + ): CoreQueryBuilder { $qb = $this->getQueryBuilder(); - $qb->generateSelect(self::TABLE_CIRCLE, self::$tables[self::TABLE_CIRCLE], $alias, true) - ->generateGroupBy(self::$tables[self::TABLE_CIRCLE], $alias) - ->orderBy($alias . '.creation', 'asc'); + $qb->generateSelect(self::TABLE_CIRCLE, self::$tables[self::TABLE_CIRCLE], $alias, !$single) + ->generateGroupBy(self::$tables[self::TABLE_CIRCLE], $alias); + + if (!$single) { + $qb->orderBy($alias . '.creation', 'asc'); + } return $qb; } diff --git a/lib/Db/CoreQueryBuilder.php b/lib/Db/CoreQueryBuilder.php index a87815fc2..06f1085f3 100644 --- a/lib/Db/CoreQueryBuilder.php +++ b/lib/Db/CoreQueryBuilder.php @@ -639,7 +639,7 @@ public function limitToDirectMembership(string $alias, Member $member): void { if ($getData) { $this->generateMemberSelectAlias($aliasMember); } - $this->leftJoin( + $this->innerJoin( $this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_MEMBER, $aliasMember, $expr->eq($aliasMember . '.circle_id', $alias . '.unique_id') ); diff --git a/lib/Service/FederatedUserService.php b/lib/Service/FederatedUserService.php index da78eb3d8..2f9aebbad 100644 --- a/lib/Service/FederatedUserService.php +++ b/lib/Service/FederatedUserService.php @@ -31,6 +31,8 @@ namespace OCA\Circles\Service; +use ArtificialOwl\MySmallPhpTools\Exceptions\InvalidItemException; +use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Deserialize; use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc22\TNC22Logger; use ArtificialOwl\MySmallPhpTools\Traits\TArrayTools; use ArtificialOwl\MySmallPhpTools\Traits\TStringTools; @@ -69,6 +71,8 @@ use OCA\Circles\Model\ManagedModel; use OCA\Circles\Model\Member; use OCA\Circles\Model\Probes\CircleProbe; +use OCP\ICache; +use OCP\ICacheFactory; use OCP\IGroupManager; use OCP\IUser; use OCP\IUserManager; @@ -83,8 +87,12 @@ class FederatedUserService { use TArrayTools; use TStringTools; use TNC22Logger; + use TNC22Deserialize; + public const CACHE_SINGLE_CIRCLE = 'circles/singleCircle'; + public const CACHE_SINGLE_CIRCLE_TTL = 900; + public const CONFLICT_001 = 1; public const CONFLICT_002 = 2; public const CONFLICT_003 = 3; @@ -129,6 +137,9 @@ class FederatedUserService { private $configService; + /** @var ICache */ + private $cache; + /** @var FederatedUser */ private $currentUser = null; @@ -154,6 +165,7 @@ class FederatedUserService { * @param IUserSession $userSession * @param IUserManager $userManager * @param IGroupManager $groupManager + * @param ICacheFactory $cacheFactory * @param FederatedEventService $federatedEventService * @param MembershipService $membershipService * @param CircleRequest $circleRequest @@ -168,6 +180,7 @@ public function __construct( IUserSession $userSession, IUserManager $userManager, IGroupManager $groupManager, + ICacheFactory $cacheFactory, FederatedEventService $federatedEventService, MembershipService $membershipService, CircleRequest $circleRequest, @@ -191,6 +204,8 @@ public function __construct( $this->interfaceService = $interfaceService; $this->configService = $configService; + $this->cache = $cacheFactory->createDistributed(self::CACHE_SINGLE_CIRCLE); + if (OC::$CLI) { $this->setInitiatedByOcc(true); } @@ -694,6 +709,8 @@ public function deleteFederatedUser(FederatedUser $federatedUser): void { $this->circleRequest->deleteFederatedUser($federatedUser); $this->memberRequest->deleteFederatedUser($federatedUser); $this->membershipService->deleteFederatedUser($federatedUser); + + $this->cache->remove($this->generateCacheKey($federatedUser)); } @@ -908,7 +925,12 @@ private function getSingleCircle(FederatedUser $federatedUser, bool $generate = } try { - return $this->circleRequest->getSingleCircle($federatedUser); + return $this->getCachedSingleCircle($federatedUser); + } catch (SingleCircleNotFoundException $e) { + } + + try { + $singleCircle = $this->circleRequest->getSingleCircle($federatedUser); } catch (SingleCircleNotFoundException $e) { if (!$generate) { throw new SingleCircleNotFoundException(); @@ -959,9 +981,13 @@ private function getSingleCircle(FederatedUser $federatedUser, bool $generate = $this->memberRequest->save($owner); $this->membershipService->onUpdate($id); + + $singleCircle = $this->circleRequest->getSingleCircle($federatedUser); } - return $this->circleRequest->getSingleCircle($federatedUser); + $this->cacheSingleCircle($federatedUser, $singleCircle); + + return $singleCircle; } @@ -1153,4 +1179,49 @@ public function getGroupCircle(string $groupId): Circle { return $circle; } + + + /** + * @param FederatedUser $federatedUser + * + * @return Circle + * @throws SingleCircleNotFoundException + */ + private function getCachedSingleCircle(FederatedUser $federatedUser): Circle { + $key = $this->generateCacheKey($federatedUser); + $cachedData = $this->cache->get($key); + + if ($cachedData === null) { + throw new SingleCircleNotFoundException(); + } + + try { + /** @var Circle $singleCircle */ + $singleCircle = $this->deserializeJson($cachedData, Circle::class); + } catch (InvalidItemException $e) { + throw new SingleCircleNotFoundException(); + } + + return $singleCircle; + } + + /** + * @param FederatedUser $federatedUser + * @param Circle $singleCircle + */ + private function cacheSingleCircle(FederatedUser $federatedUser, Circle $singleCircle): void { + $key = $this->generateCacheKey($federatedUser); + $this->cache->set($key, json_encode($singleCircle), self::CACHE_SINGLE_CIRCLE_TTL); + } + + /** + * @param FederatedUser $federatedUser + * + * @return string + */ + private function generateCacheKey(FederatedUser $federatedUser): string { + return $federatedUser->getInstance() . '#' + . $federatedUser->getUserType() . '#' + . $federatedUser->getUserId(); + } }