mirror of
https://github.com/nextcloud/server.git
synced 2026-03-11 10:51:43 -04:00
Merge pull request #44969 from nextcloud/backport/44858/stable29
[stable29] Support multiple scopes in DAV search
This commit is contained in:
commit
ed6a97cd61
1 changed files with 74 additions and 17 deletions
|
|
@ -30,6 +30,7 @@ use OC\Files\Search\SearchBinaryOperator;
|
|||
use OC\Files\Search\SearchComparison;
|
||||
use OC\Files\Search\SearchOrder;
|
||||
use OC\Files\Search\SearchQuery;
|
||||
use OC\Files\Storage\Wrapper\Jail;
|
||||
use OC\Files\View;
|
||||
use OCA\DAV\Connector\Sabre\CachingTree;
|
||||
use OCA\DAV\Connector\Sabre\Directory;
|
||||
|
|
@ -39,6 +40,8 @@ use OCP\Files\Cache\ICacheEntry;
|
|||
use OCP\Files\Folder;
|
||||
use OCP\Files\IRootFolder;
|
||||
use OCP\Files\Node;
|
||||
use OCP\Files\Search\ISearchBinaryOperator;
|
||||
use OCP\Files\Search\ISearchComparison;
|
||||
use OCP\Files\Search\ISearchOperator;
|
||||
use OCP\Files\Search\ISearchOrder;
|
||||
use OCP\Files\Search\ISearchQuery;
|
||||
|
|
@ -152,28 +155,74 @@ class FileSearchBackend implements ISearchBackend {
|
|||
public function preloadPropertyFor(array $nodes, array $requestProperties): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Query $search
|
||||
* @return SearchResult[]
|
||||
*/
|
||||
public function search(Query $search): array {
|
||||
if (count($search->from) !== 1) {
|
||||
throw new \InvalidArgumentException('Searching more than one folder is not supported');
|
||||
}
|
||||
$query = $this->transformQuery($search);
|
||||
$scope = $search->from[0];
|
||||
if ($scope->path === null) {
|
||||
private function getFolderForPath(?string $path = null): Folder {
|
||||
if ($path === null) {
|
||||
throw new \InvalidArgumentException('Using uri\'s as scope is not supported, please use a path relative to the search arbiter instead');
|
||||
}
|
||||
$node = $this->tree->getNodeForPath($scope->path);
|
||||
|
||||
$node = $this->tree->getNodeForPath($path);
|
||||
|
||||
if (!$node instanceof Directory) {
|
||||
throw new \InvalidArgumentException('Search is only supported on directories');
|
||||
}
|
||||
|
||||
$fileInfo = $node->getFileInfo();
|
||||
$folder = $this->rootFolder->get($fileInfo->getPath());
|
||||
/** @var Folder $folder $results */
|
||||
$results = $folder->search($query);
|
||||
|
||||
/** @var Folder */
|
||||
return $this->rootFolder->get($fileInfo->getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Query $search
|
||||
* @return SearchResult[]
|
||||
*/
|
||||
public function search(Query $search): array {
|
||||
switch (count($search->from)) {
|
||||
case 0:
|
||||
throw new \InvalidArgumentException('You need to specify a scope for the search.');
|
||||
break;
|
||||
case 1:
|
||||
$scope = $search->from[0];
|
||||
$folder = $this->getFolderForPath($scope->path);
|
||||
$query = $this->transformQuery($search);
|
||||
$results = $folder->search($query);
|
||||
break;
|
||||
default:
|
||||
$scopes = [];
|
||||
foreach ($search->from as $scope) {
|
||||
$folder = $this->getFolderForPath($scope->path);
|
||||
$folderStorage = $folder->getStorage();
|
||||
if ($folderStorage->instanceOfStorage(Jail::class)) {
|
||||
/** @var Jail $folderStorage */
|
||||
$internalPath = $folderStorage->getUnjailedPath($folder->getInternalPath());
|
||||
} else {
|
||||
$internalPath = $folder->getInternalPath();
|
||||
}
|
||||
|
||||
$scopes[] = new SearchBinaryOperator(
|
||||
ISearchBinaryOperator::OPERATOR_AND,
|
||||
[
|
||||
new SearchComparison(
|
||||
ISearchComparison::COMPARE_EQUAL,
|
||||
'storage',
|
||||
$folderStorage->getCache()->getNumericStorageId(),
|
||||
''
|
||||
),
|
||||
new SearchComparison(
|
||||
ISearchComparison::COMPARE_LIKE,
|
||||
'path',
|
||||
$internalPath . '/%',
|
||||
''
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$scopeOperators = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, $scopes);
|
||||
$query = $this->transformQuery($search, $scopeOperators);
|
||||
$userFolder = $this->rootFolder->getUserFolder($this->user->getUID());
|
||||
$results = $userFolder->search($query);
|
||||
}
|
||||
|
||||
/** @var SearchResult[] $nodes */
|
||||
$nodes = array_map(function (Node $node) {
|
||||
|
|
@ -288,7 +337,7 @@ class FileSearchBackend implements ISearchBackend {
|
|||
*
|
||||
* @return ISearchQuery
|
||||
*/
|
||||
private function transformQuery(Query $query): ISearchQuery {
|
||||
private function transformQuery(Query $query, ?SearchBinaryOperator $scopeOperators = null): ISearchQuery {
|
||||
$orders = array_map(function (Order $order): ISearchOrder {
|
||||
$direction = $order->order === Order::ASC ? ISearchOrder::DIRECTION_ASCENDING : ISearchOrder::DIRECTION_DESCENDING;
|
||||
if (str_starts_with($order->property->name, FilesPlugin::FILE_METADATA_PREFIX)) {
|
||||
|
|
@ -316,8 +365,16 @@ class FileSearchBackend implements ISearchBackend {
|
|||
throw new \InvalidArgumentException('Invalid search query, maximum operator limit of ' . self::OPERATOR_LIMIT . ' exceeded, got ' . $operatorCount . ' operators');
|
||||
}
|
||||
|
||||
/** @var SearchBinaryOperator|SearchComparison */
|
||||
$queryOperators = $this->transformSearchOperation($query->where);
|
||||
if ($scopeOperators === null) {
|
||||
$operators = $queryOperators;
|
||||
} else {
|
||||
$operators = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [$queryOperators, $scopeOperators]);
|
||||
}
|
||||
|
||||
return new SearchQuery(
|
||||
$this->transformSearchOperation($query->where),
|
||||
$operators,
|
||||
(int)$limit->maxResults,
|
||||
$offset,
|
||||
$orders,
|
||||
|
|
|
|||
Loading…
Reference in a new issue