From b1286341d3124548e0121620e74cf12ab5f1f8cb Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Fri, 2 Dec 2022 13:28:43 +0100 Subject: [PATCH] new OCS route to get info on discoverable/searchable reference providers Signed-off-by: Julien Veyssier --- core/Controller/ReferenceApiController.php | 13 +++ core/routes.php | 1 + .../Reference/ReferenceManager.php | 86 +++++++++++++++++++ 3 files changed, 100 insertions(+) diff --git a/core/Controller/ReferenceApiController.php b/core/Controller/ReferenceApiController.php index 266532113d888..bd1c05ef473fa 100644 --- a/core/Controller/ReferenceApiController.php +++ b/core/Controller/ReferenceApiController.php @@ -27,6 +27,8 @@ use OCP\AppFramework\Http\DataResponse; use OCP\Collaboration\Reference\IReferenceManager; use OCP\IRequest; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; class ReferenceApiController extends \OCP\AppFramework\OCSController { private IReferenceManager $referenceManager; @@ -88,4 +90,15 @@ public function resolve(array $references, int $limit = 1): DataResponse { 'references' => array_filter($result) ]); } + + /** + * @NoAdminRequired + * + * @return DataResponse + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function getProvidersInfo(): DataResponse { + return new DataResponse($this->referenceManager->getDiscoverableProviders()); + } } diff --git a/core/routes.php b/core/routes.php index a3fdfafd7bf08..4b67dee43f9a9 100644 --- a/core/routes.php +++ b/core/routes.php @@ -134,6 +134,7 @@ ['root' => '/references', 'name' => 'ReferenceApi#resolveOne', 'url' => '/resolve', 'verb' => 'GET'], ['root' => '/references', 'name' => 'ReferenceApi#extract', 'url' => '/extract', 'verb' => 'POST'], ['root' => '/references', 'name' => 'ReferenceApi#resolve', 'url' => '/resolve', 'verb' => 'POST'], + ['root' => '/references', 'name' => 'ReferenceApi#getProvidersInfo', 'url' => '/providers', 'verb' => 'GET'], ['root' => '/profile', 'name' => 'ProfileApi#setVisibility', 'url' => '/{targetUserId}', 'verb' => 'PUT'], diff --git a/lib/private/Collaboration/Reference/ReferenceManager.php b/lib/private/Collaboration/Reference/ReferenceManager.php index a11d92fe2a9ff..0073ba39b537f 100644 --- a/lib/private/Collaboration/Reference/ReferenceManager.php +++ b/lib/private/Collaboration/Reference/ReferenceManager.php @@ -26,14 +26,18 @@ use OC\AppFramework\Bootstrap\Coordinator; use OC\Collaboration\Reference\File\FileReferenceProvider; +use OCP\Collaboration\Reference\IDiscoverableReferenceProvider; use OCP\Collaboration\Reference\IReference; use OCP\Collaboration\Reference\IReferenceManager; use OCP\Collaboration\Reference\IReferenceProvider; +use OCP\Collaboration\Reference\ISearchableReferenceProvider; use OCP\Collaboration\Reference\Reference; use OCP\ICache; use OCP\ICacheFactory; use OCP\IURLGenerator; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use Psr\Log\LoggerInterface; use Throwable; @@ -56,6 +60,12 @@ public function __construct(LinkReferenceProvider $linkReferenceProvider, ICache $this->logger = $logger; } + /** + * Extract a list of URLs from a text + * + * @param string $text + * @return array|string[] + */ public function extractReferences(string $text): array { preg_match_all(IURLGenerator::URL_REGEX, $text, $matches); $references = $matches[0] ?? []; @@ -64,6 +74,14 @@ public function extractReferences(string $text): array { }, $references); } + /** + * Try to get a cached reference object from a reference string + * + * @param string $referenceId + * @return IReference|null + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ public function getReferenceFromCache(string $referenceId): ?IReference { $matchedProvider = $this->getMatchedProvider($referenceId); @@ -75,6 +93,12 @@ public function getReferenceFromCache(string $referenceId): ?IReference { return $this->getReferenceByCacheKey($cacheKey); } + /** + * Try to get a cached reference object from a full cache key + * + * @param string $cacheKey + * @return IReference|null + */ public function getReferenceByCacheKey(string $cacheKey): ?IReference { $cached = $this->cache->get($cacheKey); if ($cached) { @@ -84,6 +108,15 @@ public function getReferenceByCacheKey(string $cacheKey): ?IReference { return null; } + /** + * Get a reference object from a reference string with a matching provider + * Use a cached reference if possible + * + * @param string $referenceId + * @return IReference|null + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ public function resolveReference(string $referenceId): ?IReference { $matchedProvider = $this->getMatchedProvider($referenceId); @@ -106,6 +139,15 @@ public function resolveReference(string $referenceId): ?IReference { return null; } + /** + * Try to match a reference string with all the registered providers + * Fallback to the link reference provider (using OpenGraph) + * + * @param string $referenceId + * @return IReferenceProvider|null the first matching provider + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ private function getMatchedProvider(string $referenceId): ?IReferenceProvider { $matchedProvider = null; foreach ($this->getProviders() as $provider) { @@ -122,6 +164,13 @@ private function getMatchedProvider(string $referenceId): ?IReferenceProvider { return $matchedProvider; } + /** + * Get a hashed full cache key from a key and prefix given by a provider + * + * @param IReferenceProvider $provider + * @param string $referenceId + * @return string + */ private function getFullCacheKey(IReferenceProvider $provider, string $referenceId): string { $cacheKey = $provider->getCacheKey($referenceId); return md5($provider->getCachePrefix($referenceId)) . ( @@ -129,6 +178,13 @@ private function getFullCacheKey(IReferenceProvider $provider, string $reference ); } + /** + * Remove a specific cache entry from its key+prefix + * + * @param string $cachePrefix + * @param string|null $cacheKey + * @return void + */ public function invalidateCache(string $cachePrefix, ?string $cacheKey = null): void { if ($cacheKey === null) { $this->cache->clear(md5($cachePrefix)); @@ -140,6 +196,8 @@ public function invalidateCache(string $cachePrefix, ?string $cacheKey = null): /** * @return IReferenceProvider[] + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface */ public function getProviders(): array { if ($this->providers === null) { @@ -167,4 +225,32 @@ public function getProviders(): array { return $this->providers; } + + /** + * Get information on discoverable reference providers (id, title, icon and order) + * If the provider is searchable, also get the list of supported unified search providers + * + * @return IDiscoverableReferenceProvider[] + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function getDiscoverableProviders(): array { + $discoverableProviders = array_filter($this->getProviders(), static function (IReferenceProvider $provider) { + return $provider instanceof IDiscoverableReferenceProvider; + }); + // preserve 0 based index to avoid returning an object in data responses + $discoverableProviders = array_values($discoverableProviders); + return array_map(static function (IDiscoverableReferenceProvider $provider) { + $providerInfo = [ + 'id' => $provider->getId(), + 'title' => $provider->getTitle(), + 'icon' => $provider->getIconClass(), + 'order' => $provider->getOrder(), + ]; + if ($provider instanceof ISearchableReferenceProvider) { + $providerInfo['search_providers_ids'] = $provider->getSupportedSearchProviderIds(); + } + return $providerInfo; + }, $discoverableProviders); + } }