Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0e90eb5
Adding search files functionality in Paperless from Nextcloud
Jin-Di Dec 13, 2024
0b2be22
Fix indentation and apply coding standards, add the copyright of the …
Jin-Di Dec 17, 2024
d9f6a88
Reverted package.json and package-lock.json to original state
Jin-Di Dec 17, 2024
80c192c
Modified ApiService.php, implement the call directly like it is done …
Jin-Di Dec 17, 2024
49254f7
Remove thumbnail URL function.
Jin-Di Dec 17, 2024
feb3dc7
Fix pagination feature
Jin-Di Dec 18, 2024
72bea30
Move strip_tag to initialization
Jin-Di Dec 18, 2024
f6b0bd1
Update lib/Service/ApiService.php
Jin-Di Dec 19, 2024
e392558
Update lib/Service/ApiService.php
Jin-Di Dec 19, 2024
96dd592
Remove controller and change the limit
Jin-Di Dec 19, 2024
dcb65fa
Merge branch 'feature/add-search-function-for-nextcloud' of github.co…
Jin-Di Dec 19, 2024
2e576db
Fix error handling
Jin-Di Dec 19, 2024
a636dfe
Update ApiService.php
Jin-Di Dec 19, 2024
6f597e6
Update lib/Search/SearchProvider.php
Jin-Di Dec 19, 2024
559302b
Update lib/Search/SearchProvider.php
Jin-Di Dec 19, 2024
f22e30f
Signed-off-by: Goh Jin Di <jdgoh334@gmail.com>
Jin-Di Dec 19, 2024
b46d32b
Merge branch 'feature/add-search-function-for-nextcloud' of github.co…
Jin-Di Dec 19, 2024
78fcaa2
Update function name and params
Jin-Di Dec 19, 2024
4efb291
Unified indentation
Jin-Di Dec 19, 2024
3fb8924
Fix pagination
Jin-Di Dec 19, 2024
e2028b3
Some changes
Jin-Di Dec 20, 2024
19eb4b8
Merge branch 'nextcloud:main' into feature/add-search-function-for-ne…
Jin-Di Dec 20, 2024
c045eb6
Fix pagination
Jin-Di Dec 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down
120 changes: 120 additions & 0 deletions lib/Search/SearchProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php

/**
* This file contains code derived from Nextcloud - Zulip
* @copyright Copyright (c) 2024, Edward Ly
*
* @author Edward Ly <contact@edward.ly>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add yourself to this authors list

* @author Goh Jin Di <jdgoh334@gmail.com>
* @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 <http://www.gnu.org/licenses/>
*
*/

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'] ?? '#');
}
}
45 changes: 45 additions & 0 deletions lib/Service/ApiService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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;
}
}
2 changes: 1 addition & 1 deletion lib/Settings/SettingsSection.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
class SettingsSection implements IIconSection {
public function __construct(
private IURLGenerator $urlGenerator,
private IL10N $l
private IL10N $l,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary change, you're not even changing anything else in this file

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is the change made from the composer cs:fix, shall we just leave it?

) {
}

Expand Down