diff --git a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php index 04dd28ff2fe3..8aa9e4d2d7a9 100644 --- a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php @@ -23,6 +23,7 @@ namespace OCA\DAV\Connector\Sabre; use OC\Files\View; +use OCA\DAV\Files\Xml\FilterRequest; use Sabre\DAV\Exception\PreconditionFailed; use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\ServerPlugin; @@ -138,6 +139,8 @@ public function initialize(\Sabre\DAV\Server $server) { $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc'; + $server->xml->elementMap[self::REPORT_NAME] = FilterRequest::class; + $this->server = $server; $this->server->on('report', [$this, 'onReport']); } @@ -158,7 +161,7 @@ public function getSupportedReportSet($uri) { * REPORT operations to look for files * * @param string $reportName - * @param $report + * @param mixed $report * @param string $uri * @return bool * @throws BadRequest @@ -166,43 +169,36 @@ public function getSupportedReportSet($uri) { * @internal param $ [] $report */ public function onReport($reportName, $report, $uri) { + $reportTargetNode = $this->server->tree->getNodeForPath($uri); if (!$reportTargetNode instanceof Directory || $reportName !== self::REPORT_NAME) { return; } - $ns = '{' . $this::NS_OWNCLOUD . '}'; - $requestedProps = []; - $filterRules = []; - - // parse report properties and gather filter info - foreach ($report as $reportProps) { - $name = $reportProps['name']; - if ($name === $ns . 'filter-rules') { - $filterRules = $reportProps['value']; - } else if ($name === '{DAV:}prop') { - // propfind properties - foreach ($reportProps['value'] as $propVal) { - $requestedProps[] = $propVal['name']; - } + $requestedProps = $report->properties; + $filterRules = $report->filters; + + if (empty($filterRules['systemtag']) && is_null($filterRules['favorite'])) { + // load all + $results = $reportTargetNode->getChildren(); + } else { + // gather all file ids matching filter + try { + $resultFileIds = $this->processFilterRules($filterRules); + } catch (TagNotFoundException $e) { + throw new PreconditionFailed('Cannot filter by non-existing tag', 0, $e); } - } - if (empty($filterRules)) { - // an empty filter would return all existing files which would be slow - throw new BadRequest('Missing filter-rule block in request'); + // find sabre nodes by file id, restricted to the root node path + $results = $this->findNodesByFileIds($reportTargetNode, $resultFileIds); } - // gather all file ids matching filter - try { - $resultFileIds = $this->processFilterRules($filterRules); - } catch (TagNotFoundException $e) { - throw new PreconditionFailed('Cannot filter by non-existing tag', 0, $e); + if (!is_null($report->limit)) { + $length = $report->limit['size']; + $offset = $report->limit['page'] * $length; + $results = array_slice($results, $offset, $length); } - // find sabre nodes by file id, restricted to the root node path - $results = $this->findNodesByFileIds($reportTargetNode, $resultFileIds); - $filesUri = $this->getFilesBaseUri($uri, $reportTargetNode->getPath()); $responses = $this->prepareResponses($filesUri, $requestedProps, $results); @@ -251,18 +247,9 @@ private function getFilesBaseUri($uri, $subPath) { * @throws TagNotFoundException whenever a tag was not found */ protected function processFilterRules($filterRules) { - $ns = '{' . $this::NS_OWNCLOUD . '}'; $resultFileIds = null; - $systemTagIds = []; - $favoriteFilter = null; - foreach ($filterRules as $filterRule) { - if ($filterRule['name'] === $ns . 'systemtag') { - $systemTagIds[] = $filterRule['value']; - } - if ($filterRule['name'] === $ns . 'favorite') { - $favoriteFilter = true; - } - } + $systemTagIds = $filterRules['systemtag']; + $favoriteFilter = $filterRules['favorite']; if ($favoriteFilter !== null) { $resultFileIds = $this->fileTagger->load('files')->getFavorites(); diff --git a/apps/dav/lib/Files/Xml/FilterRequest.php b/apps/dav/lib/Files/Xml/FilterRequest.php new file mode 100644 index 000000000000..aeda47abfbc5 --- /dev/null +++ b/apps/dav/lib/Files/Xml/FilterRequest.php @@ -0,0 +1,104 @@ +next(); + * + * $reader->parseInnerTree() will parse the entire sub-tree, and advance to + * the next element. + * + * @param Reader $reader + * @return mixed + */ + static function xmlDeserialize(Reader $reader) { + $elems = (array)$reader->parseInnerTree([ + '{DAV:}prop' => KeyValue::class, + '{http://owncloud.org/ns}filter-rules' => Base::class, + '{http://owncloud.org/ns}limit' => Base::class + ]); + + $newProps = [ + 'filters' => [ + 'systemtag' => [], + 'favorite' => null + ], + 'properties' => [], + 'limit' => null, + ]; + + if (!is_array($elems)) { + $elems = []; + } + + foreach ($elems as $elem) { + + switch ($elem['name']) { + + case '{DAV:}prop' : + $newProps['properties'] = array_keys($elem['value']); + break; + case '{http://owncloud.org/ns}filter-rules' : + + foreach ($elem['value'] as $tag) { + if ($tag['name'] === '{http://owncloud.org/ns}systemtag') { + $newProps['filters']['systemtag'][] = $tag['value']; + } + if ($tag['name'] === '{http://owncloud.org/ns}favorite') { + $newProps['filters']['favorite'] = true; + } + } + break; + case '{http://owncloud.org/ns}limit' : + // TODO verify page and size + $newProps['limit'] = $elem['attributes']; + break; + + } + + } + + $obj = new self(); + foreach ($newProps as $key => $value) { + $obj->$key = $value; + } + + return $obj; + } +} diff --git a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php index eccfa4c7abf0..5f5ccc166995 100644 --- a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php +++ b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php @@ -24,6 +24,7 @@ namespace OCA\DAV\Tests\unit\Connector\Sabre; use OCA\DAV\Connector\Sabre\FilesReportPlugin as FilesReportPluginImplementation; +use OCA\DAV\Files\Xml\FilterRequest; use OCP\SystemTag\ISystemTagObjectMapper; use OC\Files\View; use OCP\Files\Folder; @@ -154,21 +155,11 @@ public function testOnReportInvalidReportName() { public function testOnReport() { $path = 'test'; - $parameters = [ - [ - 'name' => '{DAV:}prop', - 'value' => [ - ['name' => '{DAV:}getcontentlength', 'value' => ''], - ['name' => '{http://owncloud.org/ns}size', 'value' => ''], - ], - ], - [ - 'name' => '{http://owncloud.org/ns}filter-rules', - 'value' => [ - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'], - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'], - ], - ], + $parameters = new FilterRequest(); + $parameters->properties = ['{DAV:}getcontentlength', '{http://owncloud.org/ns}size']; + $parameters->filters = [ + 'systemtag' => [123, 456], + 'favorite' => null ]; $this->groupManager->expects($this->any()) @@ -400,7 +391,8 @@ public function testProcessFilterRulesSingle() { ]); $rules = [ - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'], + 'systemtag' => ['123'], + 'favorite' => null ]; $this->assertEquals(['111', '222'], $this->invokePrivate($this->plugin, 'processFilterRules', [$rules])); @@ -422,9 +414,10 @@ public function testProcessFilterRulesAndCondition() { ['456', 'files', 0, '', ['222', '333']], ]); + $rules = [ - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'], - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'], + 'systemtag' => ['123', '456'], + 'favorite' => null ]; $this->assertEquals(['222'], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules]))); @@ -447,8 +440,8 @@ public function testProcessFilterRulesAndConditionWithOneEmptyResult() { ]); $rules = [ - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'], - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'], + 'systemtag' => ['123', '456'], + 'favorite' => null ]; $this->assertEquals([], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules]))); @@ -471,8 +464,8 @@ public function testProcessFilterRulesAndConditionWithFirstEmptyResult() { ]); $rules = [ - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'], - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'], + 'systemtag' => ['123', '456'], + 'favorite' => null ]; $this->assertEquals([], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules]))); @@ -497,9 +490,8 @@ public function testProcessFilterRulesAndConditionWithEmptyMidResult() { ]); $rules = [ - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'], - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'], - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '789'], + 'systemtag' => ['123', '456', '789'], + 'favorite' => null ]; $this->assertEquals([], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules]))); @@ -540,8 +532,8 @@ public function testProcessFilterRulesInvisibleTagAsAdmin() { ->will($this->returnValue(['222', '333'])); $rules = [ - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'], - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'], + 'systemtag' => ['123', '456'], + 'favorite' => null ]; $this->assertEquals(['222'], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules]))); @@ -577,8 +569,8 @@ public function testProcessFilterRulesInvisibleTagAsUser() { ->will($this->returnValue([$tag1, $tag2])); $rules = [ - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'], - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'], + 'systemtag' => ['123', '456'], + 'favorite' => null ]; $this->invokePrivate($this->plugin, 'processFilterRules', [$rules]); @@ -620,8 +612,8 @@ public function testProcessFilterRulesVisibleTagAsUser() { ->will($this->returnValue(['222', '333'])); $rules = [ - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '123'], - ['name' => '{http://owncloud.org/ns}systemtag', 'value' => '456'], + 'systemtag' => ['123', '456'], + 'favorite' => null ]; $this->assertEquals(['222'], array_values($this->invokePrivate($this->plugin, 'processFilterRules', [$rules]))); @@ -629,7 +621,8 @@ public function testProcessFilterRulesVisibleTagAsUser() { public function testProcessFavoriteFilter() { $rules = [ - ['name' => '{http://owncloud.org/ns}favorite', 'value' => '1'], + 'systemtag' => [], + 'favorite' => true ]; $this->privateTags->expects($this->once())