aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav/lib/Files/FileSearchBackend.php
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2019-11-08 15:05:21 +0100
committerJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>2019-12-03 13:49:37 +0100
commitc62637da8b42ec184c252e3152bb033bd8f11561 (patch)
tree24c69bdaeb65a7900ba080cd9a1d5262efc496e1 /apps/dav/lib/Files/FileSearchBackend.php
parent2b19da84d5488ea35c6c27c26c78678fd8c5affb (diff)
downloadnextcloud-server-c62637da8b42ec184c252e3152bb033bd8f11561.tar.gz
nextcloud-server-c62637da8b42ec184c252e3152bb033bd8f11561.zip
Allow filtering the search results to the users home storage
This is done by adding a ```xml <d:eq> <d:prop> <oc:owner-id/> </d:prop> <d:literal>$userId</d:literal> </d:eq> ``` clause to the search query. Searching by `owner-id` can only be done with the current user id and the comparison can not be inside a `<d:not>` or `<d:or>` statement Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'apps/dav/lib/Files/FileSearchBackend.php')
-rw-r--r--apps/dav/lib/Files/FileSearchBackend.php82
1 files changed, 75 insertions, 7 deletions
diff --git a/apps/dav/lib/Files/FileSearchBackend.php b/apps/dav/lib/Files/FileSearchBackend.php
index 3eba158c944..6c1f279c6bd 100644
--- a/apps/dav/lib/Files/FileSearchBackend.php
+++ b/apps/dav/lib/Files/FileSearchBackend.php
@@ -119,6 +119,7 @@ class FileSearchBackend implements ISearchBackend {
new SearchPropertyDefinition(FilesPlugin::SIZE_PROPERTYNAME, true, true, true, SearchPropertyDefinition::DATATYPE_NONNEGATIVE_INTEGER),
new SearchPropertyDefinition(TagsPlugin::FAVORITE_PROPERTYNAME, true, true, true, SearchPropertyDefinition::DATATYPE_BOOLEAN),
new SearchPropertyDefinition(FilesPlugin::INTERNAL_FILEID_PROPERTYNAME, true, true, false, SearchPropertyDefinition::DATATYPE_NONNEGATIVE_INTEGER),
+ new SearchPropertyDefinition(FilesPlugin::OWNER_ID_PROPERTYNAME, true, true, false),
// select only properties
new SearchPropertyDefinition('{DAV:}resourcetype', false, true, false),
@@ -126,7 +127,6 @@ class FileSearchBackend implements ISearchBackend {
new SearchPropertyDefinition(FilesPlugin::CHECKSUMS_PROPERTYNAME, false, true, false),
new SearchPropertyDefinition(FilesPlugin::PERMISSIONS_PROPERTYNAME, false, true, false),
new SearchPropertyDefinition(FilesPlugin::GETETAG_PROPERTYNAME, false, true, false),
- new SearchPropertyDefinition(FilesPlugin::OWNER_ID_PROPERTYNAME, false, true, false),
new SearchPropertyDefinition(FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME, false, true, false),
new SearchPropertyDefinition(FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME, false, true, false),
new SearchPropertyDefinition(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, false, true, false, SearchPropertyDefinition::DATATYPE_BOOLEAN),
@@ -169,10 +169,12 @@ class FileSearchBackend implements ISearchBackend {
return new SearchResult($davNode, $path);
}, $results);
- // Sort again, since the result from multiple storages is appended and not sorted
- usort($nodes, function (SearchResult $a, SearchResult $b) use ($search) {
- return $this->sort($a, $b, $search->orderBy);
- });
+ if (!$query->limitToHome()) {
+ // Sort again, since the result from multiple storages is appended and not sorted
+ usort($nodes, function (SearchResult $a, SearchResult $b) use ($search) {
+ return $this->sort($a, $b, $search->orderBy);
+ });
+ }
// If a limit is provided use only return that number of files
if ($search->limit->maxResults !== 0) {
@@ -267,11 +269,29 @@ class FileSearchBackend implements ISearchBackend {
* @param Query $query
* @return ISearchQuery
*/
- private function transformQuery(Query $query) {
+ private function transformQuery(Query $query): ISearchQuery {
// TODO offset
$limit = $query->limit;
$orders = array_map([$this, 'mapSearchOrder'], $query->orderBy);
- return new SearchQuery($this->transformSearchOperation($query->where), (int)$limit->maxResults, 0, $orders, $this->user);
+
+ $limitHome = false;
+ $ownerProp = $this->extractWhereValue($query->where, FilesPlugin::OWNER_ID_PROPERTYNAME, Operator::OPERATION_EQUAL);
+ if ($ownerProp !== null) {
+ if ($ownerProp === $this->user->getUID()) {
+ $limitHome = true;
+ } else {
+ throw new \InvalidArgumentException("Invalid search value for '{http://owncloud.org/ns}owner-id', only the current user id is allowed");
+ }
+ }
+
+ return new SearchQuery(
+ $this->transformSearchOperation($query->where),
+ (int)$limit->maxResults,
+ 0,
+ $orders,
+ $this->user,
+ $limitHome
+ );
}
/**
@@ -360,4 +380,52 @@ class FileSearchBackend implements ISearchBackend {
return $value;
}
}
+
+ /**
+ * Get a specific property from the were clause
+ */
+ private function extractWhereValue(Operator &$operator, string $propertyName, string $comparison, bool $acceptableLocation = true): ?string {
+ switch ($operator->type) {
+ case Operator::OPERATION_AND:
+ case Operator::OPERATION_OR:
+ case Operator::OPERATION_NOT:
+ foreach ($operator->arguments as &$argument) {
+ $value = $this->extractWhereValue($argument, $propertyName, $comparison, $acceptableLocation && $operator->type === Operator::OPERATION_AND);
+ if ($value !== null) {
+ return $value;
+ }
+ }
+ return null;
+ case Operator::OPERATION_EQUAL:
+ case Operator::OPERATION_GREATER_OR_EQUAL_THAN:
+ case Operator::OPERATION_GREATER_THAN:
+ case Operator::OPERATION_LESS_OR_EQUAL_THAN:
+ case Operator::OPERATION_LESS_THAN:
+ case Operator::OPERATION_IS_LIKE:
+ if ($operator->arguments[0]->name === $propertyName) {
+ if ($operator->type === $comparison) {
+ if ($acceptableLocation) {
+ if ($operator->arguments[1] instanceof Literal) {
+ $value = $operator->arguments[1]->value;
+
+ // to remove the comparison from the query, we replace it with an empty AND
+ $operator = new Operator(Operator::OPERATION_AND);
+
+ return $value;
+ } else {
+ throw new \InvalidArgumentException("searching by '$propertyName' is only allowed with a literal value");
+ }
+ } else{
+ throw new \InvalidArgumentException("searching by '$propertyName' is not allowed inside a '{DAV:}or' or '{DAV:}not'");
+ }
+ } else {
+ throw new \InvalidArgumentException("searching by '$propertyName' is only allowed inside a '$comparison'");
+ }
+ } else {
+ return null;
+ }
+ default:
+ return null;
+ }
+ }
}