diff options
Diffstat (limited to 'apps/files/lib/Search/FilesSearchProvider.php')
-rw-r--r-- | apps/files/lib/Search/FilesSearchProvider.php | 169 |
1 files changed, 106 insertions, 63 deletions
diff --git a/apps/files/lib/Search/FilesSearchProvider.php b/apps/files/lib/Search/FilesSearchProvider.php index ba2d4bafa30..f71d58c6fae 100644 --- a/apps/files/lib/Search/FilesSearchProvider.php +++ b/apps/files/lib/Search/FilesSearchProvider.php @@ -3,73 +3,45 @@ declare(strict_types=1); /** - * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Joas Schilling <coding@schilljs.com> - * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Robin Appelman <robin@icewind.nl> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\Files\Search; +use InvalidArgumentException; +use OC\Files\Search\SearchBinaryOperator; use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchOrder; use OC\Files\Search\SearchQuery; +use OC\Search\Filter\GroupFilter; +use OC\Search\Filter\UserFilter; use OCP\Files\FileInfo; use OCP\Files\IMimeTypeDetector; use OCP\Files\IRootFolder; -use OCP\Files\Search\ISearchComparison; use OCP\Files\Node; +use OCP\Files\Search\ISearchComparison; +use OCP\Files\Search\ISearchOperator; use OCP\Files\Search\ISearchOrder; use OCP\IL10N; +use OCP\IPreview; use OCP\IURLGenerator; use OCP\IUser; -use OCP\Search\IProvider; +use OCP\Search\FilterDefinition; +use OCP\Search\IFilter; +use OCP\Search\IFilteringProvider; use OCP\Search\ISearchQuery; use OCP\Search\SearchResult; use OCP\Search\SearchResultEntry; +use OCP\Share\IShare; -class FilesSearchProvider implements IProvider { - - /** @var IL10N */ - private $l10n; - - /** @var IURLGenerator */ - private $urlGenerator; - - /** @var IMimeTypeDetector */ - private $mimeTypeDetector; - - /** @var IRootFolder */ - private $rootFolder; - +class FilesSearchProvider implements IFilteringProvider { public function __construct( - IL10N $l10n, - IURLGenerator $urlGenerator, - IMimeTypeDetector $mimeTypeDetector, - IRootFolder $rootFolder + private IL10N $l10n, + private IURLGenerator $urlGenerator, + private IMimeTypeDetector $mimeTypeDetector, + private IRootFolder $rootFolder, + private IPreview $previewManager, ) { - $this->l10n = $l10n; - $this->urlGenerator = $urlGenerator; - $this->mimeTypeDetector = $mimeTypeDetector; - $this->rootFolder = $rootFolder; } /** @@ -97,26 +69,49 @@ class FilesSearchProvider implements IProvider { return 5; } - /** - * @inheritDoc - */ + public function getSupportedFilters(): array { + return [ + 'term', + 'since', + 'until', + 'person', + 'min-size', + 'max-size', + 'mime', + 'type', + 'path', + 'is-favorite', + 'title-only', + ]; + } + + public function getAlternateIds(): array { + return []; + } + + public function getCustomFilters(): array { + return [ + new FilterDefinition('min-size', FilterDefinition::TYPE_INT), + new FilterDefinition('max-size', FilterDefinition::TYPE_INT), + new FilterDefinition('mime', FilterDefinition::TYPE_STRING), + new FilterDefinition('type', FilterDefinition::TYPE_STRING), + new FilterDefinition('path', FilterDefinition::TYPE_STRING), + new FilterDefinition('is-favorite', FilterDefinition::TYPE_BOOL), + ]; + } + public function search(IUser $user, ISearchQuery $query): SearchResult { $userFolder = $this->rootFolder->getUserFolder($user->getUID()); - $fileQuery = new SearchQuery( - new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query->getTerm() . '%'), - $query->getLimit(), - (int)$query->getCursor(), - $query->getSortOrder() === ISearchQuery::SORT_DATE_DESC ? [ - new SearchOrder(ISearchOrder::DIRECTION_DESCENDING, 'mtime'), - ] : [], - $user - ); - + $fileQuery = $this->buildSearchQuery($query, $user); return SearchResult::paginated( $this->l10n->t('Files'), array_map(function (Node $result) use ($userFolder) { - // Generate thumbnail url - $thumbnailUrl = $this->urlGenerator->linkToRouteAbsolute('core.Preview.getPreviewByFileId', ['x' => 32, 'y' => 32, 'fileId' => $result->getId()]); + $thumbnailUrl = $this->previewManager->isMimeSupported($result->getMimetype()) + ? $this->urlGenerator->linkToRouteAbsolute('core.Preview.getPreviewByFileId', ['x' => 32, 'y' => 32, 'fileId' => $result->getId()]) + : ''; + $icon = $result->getMimetype() === FileInfo::MIMETYPE_FOLDER + ? 'icon-folder' + : $this->mimeTypeDetector->mimeTypeIcon($result->getMimetype()); $path = $userFolder->getRelativePath($result->getPath()); // Use shortened link to centralize the various @@ -131,7 +126,7 @@ class FilesSearchProvider implements IProvider { $result->getName(), $this->formatSubline($path), $this->urlGenerator->getAbsoluteURL($link), - $result->getMimetype() === FileInfo::MIMETYPE_FOLDER ? 'icon-folder' : $this->mimeTypeDetector->mimeTypeIcon($result->getMimetype()) + $icon, ); $searchResultEntry->addAttribute('fileId', (string)$result->getId()); $searchResultEntry->addAttribute('path', $path); @@ -141,6 +136,54 @@ class FilesSearchProvider implements IProvider { ); } + private function buildSearchQuery(ISearchQuery $query, IUser $user): SearchQuery { + $comparisons = []; + foreach ($query->getFilters() as $name => $filter) { + $comparisons[] = match ($name) { + 'term' => new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $filter->get() . '%'), + 'since' => new SearchComparison(ISearchComparison::COMPARE_GREATER_THAN_EQUAL, 'mtime', $filter->get()->getTimestamp()), + 'until' => new SearchComparison(ISearchComparison::COMPARE_LESS_THAN_EQUAL, 'mtime', $filter->get()->getTimestamp()), + 'min-size' => new SearchComparison(ISearchComparison::COMPARE_GREATER_THAN_EQUAL, 'size', $filter->get()), + 'max-size' => new SearchComparison(ISearchComparison::COMPARE_LESS_THAN_EQUAL, 'size', $filter->get()), + 'mime' => new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'mimetype', $filter->get()), + 'type' => new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $filter->get() . '/%'), + 'path' => new SearchComparison(ISearchComparison::COMPARE_LIKE, 'path', 'files/' . ltrim($filter->get(), '/') . '%'), + 'person' => $this->buildPersonSearchQuery($filter), + default => throw new InvalidArgumentException('Unsupported comparison'), + }; + } + + return new SearchQuery( + new SearchBinaryOperator(SearchBinaryOperator::OPERATOR_AND, $comparisons), + $query->getLimit(), + (int)$query->getCursor(), + $query->getSortOrder() === ISearchQuery::SORT_DATE_DESC + ? [new SearchOrder(ISearchOrder::DIRECTION_DESCENDING, 'mtime')] + : [], + $user + ); + } + + private function buildPersonSearchQuery(IFilter $person): ISearchOperator { + if ($person instanceof UserFilter) { + return new SearchBinaryOperator(SearchBinaryOperator::OPERATOR_OR, [ + new SearchBinaryOperator(SearchBinaryOperator::OPERATOR_AND, [ + new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'share_with', $person->get()->getUID()), + new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'share_type', IShare::TYPE_USER), + ]), + new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'owner', $person->get()->getUID()), + ]); + } + if ($person instanceof GroupFilter) { + return new SearchBinaryOperator(SearchBinaryOperator::OPERATOR_AND, [ + new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'share_with', $person->get()->getGID()), + new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'share_type', IShare::TYPE_GROUP), + ]); + } + + throw new InvalidArgumentException('Unsupported filter type'); + } + /** * Format subline for files * |