Skip to content

Commit

Permalink
feat(dav): Support multiple scopes in DAV search
Browse files Browse the repository at this point in the history
Signed-off-by: Louis Chemineau <louis@chmn.me>
  • Loading branch information
artonge committed Apr 16, 2024
1 parent 33c4ddd commit 3cba742
Showing 1 changed file with 36 additions and 17 deletions.
53 changes: 36 additions & 17 deletions apps/dav/lib/Files/FileSearchBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
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;
Expand All @@ -39,6 +40,7 @@
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchOperator;
use OCP\Files\Search\ISearchOrder;
use OCP\Files\Search\ISearchQuery;
Expand Down Expand Up @@ -157,23 +159,37 @@ public function preloadPropertyFor(array $nodes, array $requestProperties): void
* @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) {
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);
if (!$node instanceof Directory) {
throw new \InvalidArgumentException('Search is only supported on directories');
$scopes = [];
foreach ($search->from as $scope) {
if ($scope->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);
if (!$node instanceof Directory) {
throw new \InvalidArgumentException('Search is only supported on directories');
}
$fileInfo = $node->getFileInfo();
/** @var Folder $folder */
$folder = $this->rootFolder->get($fileInfo->getPath());
$folderStorage = $folder->getStorage();
if ($folderStorage->instanceOfStorage(Jail::class)) {
/** @var Jail $folderStorage */
$internalPath = $folderStorage->getUnjailedPath($folder->getInternalPath());
} else {
$internalPath = $folder->getInternalPath();
}
$scopes[] = new SearchComparison(
'like',
'path',
$internalPath . '/%',
''
);
}

$fileInfo = $node->getFileInfo();
$folder = $this->rootFolder->get($fileInfo->getPath());
/** @var Folder $folder $results */
$results = $folder->search($query);
$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) {
Expand Down Expand Up @@ -288,7 +304,7 @@ private function getHrefForNode(Node $node) {
*
* @return ISearchQuery
*/
private function transformQuery(Query $query): ISearchQuery {
private function transformQuery(Query $query, SearchBinaryOperator $scopeOperators): 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)) {
Expand Down Expand Up @@ -316,8 +332,11 @@ private function transformQuery(Query $query): ISearchQuery {
throw new \InvalidArgumentException('Invalid search query, maximum operator limit of ' . self::OPERATOR_LIMIT . ' exceeded, got ' . $operatorCount . ' operators');
}

$queryOperators = $this->transformSearchOperation($query->where);
$operators = new SearchBinaryOperator('and', [$queryOperators, $scopeOperators]);

Check notice

Code scanning / Psalm

ArgumentTypeCoercion Note

Argument 2 of OC\Files\Search\SearchBinaryOperator::__construct expects array<array-key, OC\Files\Search\SearchBinaryOperator|OC\Files\Search\SearchComparison>, but parent type list{OCP\Files\Search\ISearchOperator, OC\Files\Search\SearchBinaryOperator} provided

return new SearchQuery(
$this->transformSearchOperation($query->where),
$operators,
(int)$limit->maxResults,
$offset,
$orders,
Expand Down

0 comments on commit 3cba742

Please sign in to comment.