diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index f806066..ca1e28b 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -5,6 +5,7 @@ namespace OCA\Paperless\AppInfo; use OCA\Paperless\Listener\FileActionListener; +use OCA\Paperless\Search\SearchProvider; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; @@ -21,6 +22,7 @@ public function __construct() { public function register(IRegistrationContext $context): void { $context->registerEventListener(LoadAdditionalScriptsEvent::class, FileActionListener::class); + $context->registerSearchProvider(SearchProvider::class); } public function boot(IBootContext $context): void { diff --git a/lib/Search/SearchProvider.php b/lib/Search/SearchProvider.php new file mode 100644 index 0000000..e6593ed --- /dev/null +++ b/lib/Search/SearchProvider.php @@ -0,0 +1,120 @@ + + * @author Goh Jin Di + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +declare(strict_types=1); + +namespace OCA\Paperless\Search; + +use OCA\Paperless\AppInfo\Application; +use OCA\Paperless\Service\ApiService; +use OCA\Paperless\Service\ConfigService; +use OCP\App\IAppManager; +use OCP\IConfig; +use OCP\IDateTimeFormatter; +use OCP\IDateTimeZone; +use OCP\IL10N; +use OCP\IURLGenerator; +use OCP\IUser; +use OCP\Search\IProvider; +use OCP\Search\ISearchQuery; +use OCP\Search\SearchResult; +use OCP\Search\SearchResultEntry; +use Psr\Log\LoggerInterface; + +class SearchProvider implements IProvider { + + public function __construct( + private LoggerInterface $logger, + private IAppManager $appManager, + private IL10N $l10n, + private IConfig $config, + private IURLGenerator $urlGenerator, + private IDateTimeFormatter $dateTimeFormatter, + private IDateTimeZone $dateTimeZone, + private ConfigService $configService, + private ApiService $apiService, + ) { + } + + public function getId(): string { + return 'paperless-search-documents'; + } + + public function getName(): string { + return $this->l10n->t('Paperless document search result'); + } + + public function getOrder(string $route, array $routeParameters): int { + return 30; // Adjust priority as needed + } + + public function search(IUser $user, ISearchQuery $query): SearchResult { + $offset = ($query->getCursor() ?? 0); + $limit = $query->getLimit(); + + $term = $query->getTerm(); + $url = $this->config->getUserValue($user->getUID(), Application::APP_ID, 'url'); + $apiKey = $this->configService->getConfig($user->getUID(), 'token'); + + if ($url === '' || $apiKey === '') { + return SearchResult::paginated($this->getName(), [], 0); + } + + $searchResult = $this->apiService->searchDocuments($user->getUID(), $term, $offset, $limit); + + if (isset($searchResult['html'])) { + return SearchResult::paginated($this->getName(), [], 0); + } + + $formattedResults = array_map(function (array $entry) use ($url): SearchResultEntry { + $finalThumbnailUrl = ''; + $title = $entry['title'] ?? 'Untitled'; + $context = strip_tags($entry['__search_hit__']['highlights'] ?? ''); + $link = $this->getLinkToPaperless($entry, $url); + return new SearchResultEntry( + $finalThumbnailUrl, + $title, + $context, + $link, + $finalThumbnailUrl, + true + ); + }, $searchResult); + + return SearchResult::paginated( + $this->getName(), + $formattedResults, + $offset + $limit + ); + } + + /** + * @param array $entry + * @param string $url + * @return string + */ + protected function getLinkToPaperless(array $entry, string $url): string { + return rtrim($url, '/') . '/documents/' . ($entry['id'] ?? '#'); + } +} diff --git a/lib/Service/ApiService.php b/lib/Service/ApiService.php index c9f9fc4..0130882 100644 --- a/lib/Service/ApiService.php +++ b/lib/Service/ApiService.php @@ -12,6 +12,7 @@ use OCP\Files\NotPermittedException; use OCP\Http\Client\IClient; use OCP\Http\Client\IClientService; +use Psr\Log\LoggerInterface; class ApiService { private IClient $client; @@ -23,6 +24,7 @@ public function __construct( private IRootFolder $root, ConfigService $configService, IClientService $clientService, + private LoggerInterface $logger, ) { $this->client = $clientService->newClient(); $this->config = $configService->getConfig(); @@ -67,4 +69,47 @@ public function sendFile(int $fileId): void { ], ); } + + public function searchDocuments(string $userId, string $term, int $offset, int $limit): array { + $arguments = [ + 'format' => 'json', + 'query' => '*' . $term . '*' , + ]; + + $allResults = []; + $currentOffset = $offset; + $remainingLimit = $limit; + $currentPage = 1; + + do { + $arguments['page'] = $currentPage; + $paperlessURL = rtrim($this->config->url, '/') . '/api/documents/?' . http_build_query($arguments); + + $result = $this->client->get($paperlessURL, + [ + 'headers' => array_merge( + $this->getAuthorizationHeaders(), + [ + 'Accept' => 'application/json' + ] + ) + ] + ); + + $body = $result->getBody(); + $jsonBody = json_decode($body, true, 512, JSON_THROW_ON_ERROR); + + // Merge the results into the total array, accounting for offset and limit + $currentResults = array_slice($jsonBody['results'], $currentOffset, $remainingLimit); + $allResults = array_merge($allResults, $currentResults); + + // Update pagination variables + $remainingLimit -= count($currentResults); + $currentOffset = 0; // Offset is only applied on the first page + $currentPage++; + + } while ($remainingLimit > 0 && !empty($jsonBody['results'])); + + return $allResults; + } } diff --git a/lib/Settings/SettingsSection.php b/lib/Settings/SettingsSection.php index ff58f81..3b6613b 100644 --- a/lib/Settings/SettingsSection.php +++ b/lib/Settings/SettingsSection.php @@ -12,7 +12,7 @@ class SettingsSection implements IIconSection { public function __construct( private IURLGenerator $urlGenerator, - private IL10N $l + private IL10N $l, ) { }