diff --git a/core/Controller/ReferenceApiController.php b/core/Controller/ReferenceApiController.php index dc88223572dd4..18228ebe90661 100644 --- a/core/Controller/ReferenceApiController.php +++ b/core/Controller/ReferenceApiController.php @@ -10,6 +10,7 @@ use OCA\Core\ResponseDefinitions; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\AnonRateLimit; use OCP\AppFramework\Http\Attribute\ApiRoute; use OCP\AppFramework\Http\DataResponse; use OCP\Collaboration\Reference\IDiscoverableReferenceProvider; @@ -62,6 +63,38 @@ public function extract(string $text, bool $resolve = false, int $limit = 1): Da ]); } + /** + * @PublicPage + * + * Extract references from a text + * + * @param string $text Text to extract from + * @param string $sharingToken Token of the public share + * @param bool $resolve Resolve the references + * @param int $limit Maximum amount of references to extract + * @return DataResponse}, array{}> + * + * 200: References returned + */ + #[ApiRoute(verb: 'POST', url: '/extractPublic', root: '/references')] + public function extractPublic(string $text, string $sharingToken, bool $resolve = false, int $limit = 1): DataResponse { + $references = $this->referenceManager->extractReferences($text); + + $result = []; + $index = 0; + foreach ($references as $reference) { + if ($index++ >= $limit) { + break; + } + + $result[$reference] = $resolve ? $this->referenceManager->resolveReference($reference, true, $sharingToken)->jsonSerialize() : null; + } + + return new DataResponse([ + 'references' => $result + ]); + } + /** * @NoAdminRequired * @@ -82,6 +115,28 @@ public function resolveOne(string $reference): DataResponse { return $response; } + /** + * @PublicPage + * + * Resolve from a public page + * + * @param string $reference Reference to resolve + * @param string $sharingToken Token of the public share + * @return DataResponse}, array{}> + * + * 200: Reference returned + */ + #[ApiRoute(verb: 'GET', url: '/resolvePublic', root: '/references')] + #[AnonRateLimit(limit: 5, period: 120)] + public function resolveOnePublic(string $reference, string $sharingToken): DataResponse { + /** @var ?CoreReference $resolvedReference */ + $resolvedReference = $this->referenceManager->resolveReference(trim($reference), true, trim($sharingToken))?->jsonSerialize(); + + $response = new DataResponse(['references' => [$reference => $resolvedReference]]); + $response->cacheFor(3600, false, true); + return $response; + } + /** * @NoAdminRequired * @@ -110,6 +165,35 @@ public function resolve(array $references, int $limit = 1): DataResponse { ]); } + /** + * @PublicPage + * + * Resolve multiple references from a public page + * + * @param string[] $references References to resolve + * @param string $sharingToken Token of the public share + * @param int $limit Maximum amount of references to resolve + * @return DataResponse}, array{}> + * + * 200: References returned + */ + #[ApiRoute(verb: 'POST', url: '/resolvePublic', root: '/references')] + public function resolvePublic(array $references, string $sharingToken, int $limit = 1): DataResponse { + $result = []; + $index = 0; + foreach ($references as $reference) { + if ($index++ >= $limit) { + break; + } + + $result[$reference] = $this->referenceManager->resolveReference($reference, true, $sharingToken)?->jsonSerialize(); + } + + return new DataResponse([ + 'references' => $result + ]); + } + /** * @NoAdminRequired * diff --git a/lib/private/Collaboration/Reference/ReferenceManager.php b/lib/private/Collaboration/Reference/ReferenceManager.php index 208c50a074b58..79047a9142d0e 100644 --- a/lib/private/Collaboration/Reference/ReferenceManager.php +++ b/lib/private/Collaboration/Reference/ReferenceManager.php @@ -11,6 +11,7 @@ use OC\AppFramework\Bootstrap\Coordinator; use OC\Collaboration\Reference\File\FileReferenceProvider; use OCP\Collaboration\Reference\IDiscoverableReferenceProvider; +use OCP\Collaboration\Reference\IPublicReferenceProvider; use OCP\Collaboration\Reference\IReference; use OCP\Collaboration\Reference\IReferenceManager; use OCP\Collaboration\Reference\IReferenceProvider; @@ -59,14 +60,14 @@ public function extractReferences(string $text): array { /** * Try to get a cached reference object from a reference string */ - public function getReferenceFromCache(string $referenceId): ?IReference { - $matchedProvider = $this->getMatchedProvider($referenceId); + public function getReferenceFromCache(string $referenceId, bool $public = false, string $sharingToken = ''): ?IReference { + $matchedProvider = $this->getMatchedProvider($referenceId, $public); if ($matchedProvider === null) { return null; } - $cacheKey = $this->getFullCacheKey($matchedProvider, $referenceId); + $cacheKey = $this->getFullCacheKey($matchedProvider, $referenceId, $public, $sharingToken); return $this->getReferenceByCacheKey($cacheKey); } @@ -86,20 +87,24 @@ public function getReferenceByCacheKey(string $cacheKey): ?IReference { * Get a reference object from a reference string with a matching provider * Use a cached reference if possible */ - public function resolveReference(string $referenceId): ?IReference { - $matchedProvider = $this->getMatchedProvider($referenceId); + public function resolveReference(string $referenceId, bool $public = false, $sharingToken = ''): ?IReference { + $matchedProvider = $this->getMatchedProvider($referenceId, $public); if ($matchedProvider === null) { return null; } - $cacheKey = $this->getFullCacheKey($matchedProvider, $referenceId); + $cacheKey = $this->getFullCacheKey($matchedProvider, $referenceId, $public, $sharingToken); $cached = $this->cache->get($cacheKey); if ($cached) { return Reference::fromCache($cached); } - $reference = $matchedProvider->resolveReference($referenceId); + if ($public) { + $reference = $matchedProvider->resolveReferencePublic($referenceId, $sharingToken); + } else { + $reference = $matchedProvider->resolveReference($referenceId); + } if ($reference) { $cachePrefix = $matchedProvider->getCachePrefix($referenceId); if ($cachePrefix !== '') { @@ -119,9 +124,12 @@ public function resolveReference(string $referenceId): ?IReference { * * @return IReferenceProvider|null the first matching provider */ - private function getMatchedProvider(string $referenceId): ?IReferenceProvider { + private function getMatchedProvider(string $referenceId, bool $public): ?IReferenceProvider { $matchedProvider = null; foreach ($this->getProviders() as $provider) { + if ($public && !($provider instanceof IPublicReferenceProvider)) { + continue; + } $matchedProvider = $provider->matchReference($referenceId) ? $provider : null; if ($matchedProvider !== null) { break; @@ -138,8 +146,13 @@ private function getMatchedProvider(string $referenceId): ?IReferenceProvider { /** * Get a hashed full cache key from a key and prefix given by a provider */ - private function getFullCacheKey(IReferenceProvider $provider, string $referenceId): string { - $cacheKey = $provider->getCacheKey($referenceId); + private function getFullCacheKey(IReferenceProvider $provider, string $referenceId, bool $public, string $sharingToken): string { + if ($public && !($provider instanceof IPublicReferenceProvider)) { + throw new \RuntimeException('Provider doesn\'t support public lookups'); + } + $cacheKey = $public + ? $provider->getCacheKeyPublic($referenceId, $sharingToken) + : $provider->getCacheKey($referenceId); return md5($provider->getCachePrefix($referenceId)) . ( $cacheKey !== null ? ('-' . md5($cacheKey)) : '' ); diff --git a/lib/public/Collaboration/Reference/IPublicReferenceProvider.php b/lib/public/Collaboration/Reference/IPublicReferenceProvider.php new file mode 100644 index 0000000000000..db6c3d3828b50 --- /dev/null +++ b/lib/public/Collaboration/Reference/IPublicReferenceProvider.php @@ -0,0 +1,33 @@ +resolveReference($referenceText); + } + /** * Populates the reference with OpenGraph data * @@ -201,4 +209,12 @@ public function getCachePrefix(string $referenceId): string { public function getCacheKey(string $referenceId): ?string { return null; } + + /** + * @inheritDoc + * @since 30.0.0 + */ + public function getCacheKeyPublic(string $referenceId, string $sharingToken): ?string { + return null; + } }