diff options
m--------- | 3rdparty | 0 | ||||
-rw-r--r-- | apps/dav/lib/CalDAV/CachedSubscription.php | 4 | ||||
-rw-r--r-- | apps/dav/lib/Files/FileSearchBackend.php | 31 | ||||
-rw-r--r-- | build/integration/features/bootstrap/CommentsContext.php | 36 | ||||
-rw-r--r-- | lib/private/Files/Cache/SearchBuilder.php | 2 | ||||
-rw-r--r-- | lib/public/Files/Search/ISearchComparison.php | 1 |
6 files changed, 61 insertions, 13 deletions
diff --git a/3rdparty b/3rdparty -Subproject d7b9f6f5f0513adc3ed652eb84b1822fb5b5303 +Subproject b3d52b32c65999204aefeb85548f95c76391d63 diff --git a/apps/dav/lib/CalDAV/CachedSubscription.php b/apps/dav/lib/CalDAV/CachedSubscription.php index dc7f66e59b4..4047f8dad0b 100644 --- a/apps/dav/lib/CalDAV/CachedSubscription.php +++ b/apps/dav/lib/CalDAV/CachedSubscription.php @@ -169,11 +169,11 @@ class CachedSubscription extends \Sabre\CalDAV\Calendar { /** * @param string $name - * @param null|resource|string $calendarData + * @param null|resource|string $data * @return null|string * @throws MethodNotAllowed */ - public function createFile($name, $calendarData = null) { + public function createFile($name, $data = null) { throw new MethodNotAllowed('Creating objects in cached subscription is not allowed'); } diff --git a/apps/dav/lib/Files/FileSearchBackend.php b/apps/dav/lib/Files/FileSearchBackend.php index 3500d6b0fb3..419a0c5ed3b 100644 --- a/apps/dav/lib/Files/FileSearchBackend.php +++ b/apps/dav/lib/Files/FileSearchBackend.php @@ -39,6 +39,7 @@ use OCP\Files\Cache\ICacheEntry; use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Node; +use OCP\Files\Search\ISearchComparison; use OCP\Files\Search\ISearchOperator; use OCP\Files\Search\ISearchOrder; use OCP\Files\Search\ISearchQuery; @@ -367,22 +368,30 @@ class FileSearchBackend implements ISearchBackend { if (count($operator->arguments) !== 2) { throw new \InvalidArgumentException('Invalid number of arguments for ' . $trimmedType . ' operation'); } - if (!($operator->arguments[0] instanceof SearchPropertyDefinition)) { - throw new \InvalidArgumentException('Invalid argument 1 for ' . $trimmedType . ' operation, expected property'); - } if (!($operator->arguments[1] instanceof Literal)) { throw new \InvalidArgumentException('Invalid argument 2 for ' . $trimmedType . ' operation, expected literal'); } - + $value = $operator->arguments[1]->value; + case Operator::OPERATION_IS_DEFINED: + if (!($operator->arguments[0] instanceof SearchPropertyDefinition)) { + throw new \InvalidArgumentException('Invalid argument 1 for ' . $trimmedType . ' operation, expected property'); + } $property = $operator->arguments[0]; - $value = $this->castValue($property, $operator->arguments[1]->value); + if (str_starts_with($property->name, FilesPlugin::FILE_METADATA_PREFIX)) { - return new SearchComparison($trimmedType, substr($property->name, strlen(FilesPlugin::FILE_METADATA_PREFIX)), $value, IMetadataQuery::EXTRA); + $field = substr($property->name, strlen(FilesPlugin::FILE_METADATA_PREFIX)); + $extra = IMetadataQuery::EXTRA; } else { - return new SearchComparison($trimmedType, $this->mapPropertyNameToColumn($property), $value); + $field = $this->mapPropertyNameToColumn($property); } - // no break + return new SearchComparison( + $trimmedType, + $field, + $this->castValue($property, $value ?? ''), + $extra ?? '' + ); + case Operator::OPERATION_IS_COLLECTION: return new SearchComparison('eq', 'mimetype', ICacheEntry::DIRECTORY_MIMETYPE); default: @@ -416,7 +425,11 @@ class FileSearchBackend implements ISearchBackend { } private function castValue(SearchPropertyDefinition $property, $value) { - switch ($property->dataType) { + if ($value === '') { + return ''; + } + + switch ($property->dataType) { case SearchPropertyDefinition::DATATYPE_BOOLEAN: return $value === 'yes'; case SearchPropertyDefinition::DATATYPE_DECIMAL: diff --git a/build/integration/features/bootstrap/CommentsContext.php b/build/integration/features/bootstrap/CommentsContext.php index ad2d752b4dd..989f34692ca 100644 --- a/build/integration/features/bootstrap/CommentsContext.php +++ b/build/integration/features/bootstrap/CommentsContext.php @@ -49,6 +49,37 @@ class CommentsContext implements \Behat\Behat\Context\Context { } } + + + /** + * get a named entry from response instead of picking a random entry from values + * + * @param string $path + * + * @return array|string + * @throws Exception + */ + private function getValueFromNamedEntries(string $path, array $response): mixed { + $next = ''; + if (str_contains($path, ' ')) { + [$key, $next] = explode(' ', $path, 2); + } else { + $key = $path; + } + + foreach ($response as $entry) { + if ($entry['name'] === $key) { + if ($next !== '') { + return $this->getValueFromNamedEntries($next, $entry['value']); + } else { + return $entry['value']; + } + } + } + + return null; + } + /** @AfterScenario */ public function teardownScenario() { $client = new \GuzzleHttp\Client(); @@ -175,7 +206,7 @@ class CommentsContext implements \Behat\Behat\Context\Context { if ($res->getStatusCode() === 207) { $service = new Sabre\Xml\Service(); $this->response = $service->parse($res->getBody()->getContents()); - $this->commentId = (int) ($this->response[0]['value'][2]['value'][0]['value'][0]['value'] ?? 0); + $this->commentId = (int) ($this->getValueFromNamedEntries('{DAV:}response {DAV:}propstat {DAV:}prop {http://owncloud.org/ns}id', $this->response ?? []) ?? 0); } } @@ -238,7 +269,8 @@ class CommentsContext implements \Behat\Behat\Context\Context { * @throws \Exception */ public function theResponseShouldContainAPropertyWithValue($key, $value) { - $keys = $this->response[0]['value'][2]['value'][0]['value']; +// $keys = $this->response[0]['value'][1]['value'][0]['value']; + $keys = $this->getValueFromNamedEntries('{DAV:}response {DAV:}propstat {DAV:}prop', $this->response); $found = false; foreach ($keys as $singleKey) { if ($singleKey['name'] === '{http://owncloud.org/ns}' . substr($key, 3)) { diff --git a/lib/private/Files/Cache/SearchBuilder.php b/lib/private/Files/Cache/SearchBuilder.php index c3699cca63d..38161ec9cc6 100644 --- a/lib/private/Files/Cache/SearchBuilder.php +++ b/lib/private/Files/Cache/SearchBuilder.php @@ -47,6 +47,7 @@ class SearchBuilder { ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'gte', ISearchComparison::COMPARE_LESS_THAN => 'lt', ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lte', + ISearchComparison::COMPARE_DEFINED => 'isNotNull', ]; protected static $searchOperatorNegativeMap = [ @@ -57,6 +58,7 @@ class SearchBuilder { ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'lt', ISearchComparison::COMPARE_LESS_THAN => 'gte', ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'gt', + ISearchComparison::COMPARE_DEFINED => 'isNull', ]; public const TAG_FAVORITE = '_$!<Favorite>!$_'; diff --git a/lib/public/Files/Search/ISearchComparison.php b/lib/public/Files/Search/ISearchComparison.php index d7313fbaf2a..ba02f39996f 100644 --- a/lib/public/Files/Search/ISearchComparison.php +++ b/lib/public/Files/Search/ISearchComparison.php @@ -35,6 +35,7 @@ interface ISearchComparison extends ISearchOperator { public const COMPARE_LESS_THAN_EQUAL = 'lte'; public const COMPARE_LIKE = 'like'; public const COMPARE_LIKE_CASE_SENSITIVE = 'clike'; + public const COMPARE_DEFINED = 'is-defined'; public const HINT_PATH_EQ_HASH = 'path_eq_hash'; // transform `path = "$path"` into `path_hash = md5("$path")`, on by default |