diff --git a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php
index 8e12971565f8..38ac9225193d 100644
--- a/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php
+++ b/apps/dav/lib/Connector/Sabre/FilesReportPlugin.php
@@ -24,6 +24,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;
@@ -139,6 +140,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']);
}
@@ -159,7 +162,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
@@ -167,50 +170,44 @@ 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;
+
+ // "systemtag" is always an array of tags, favorite a string/int/null
+ if (empty($filterRules['systemtag']) && is_null($filterRules['favorite'])) {
+ // FIXME: search currently not possible because results are missing properties!
+ throw new BadRequest('No filter criteria specified');
+ } else {
+ if (isset($report->search['pattern'])) {
+ // TODO: implement this at some point...
+ throw new BadRequest('Search pattern cannot be combined with filter');
}
- }
- if (empty($filterRules)) {
- // an empty filter would return all existing files which would be slow
- throw new BadRequest('Missing filter-rule block in request');
- }
+ // 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);
+ }
- // 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);
- }
+ // pre-slice the results if needed for pagination to not waste
+ // time resolving nodes that will not be returned anyway
+ $resultFileIds = $this->slice($resultFileIds, $report);
- // find sabre nodes by file id, restricted to the root node path
- $results = $this->findNodesByFileIds($reportTargetNode, $resultFileIds);
+ // 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);
+ $results = $this->prepareResponses($filesUri, $requestedProps, $results);
- $xml = $this->server->xml->write(
- '{DAV:}multistatus',
- new MultiStatus($responses)
- );
+ $xml = $this->server->generateMultiStatus($results);
$this->server->httpResponse->setStatus(207);
$this->server->httpResponse->setHeader('Content-Type', 'application/xml; charset=utf-8');
@@ -219,6 +216,15 @@ public function onReport($reportName, $report, $uri) {
return false;
}
+ private function slice($results, $report) {
+ if (!is_null($report->search)) {
+ $length = $report->search['limit'];
+ $offset = $report->search['offset'];
+ $results = array_slice($results, $offset, $length);
+ }
+ return $results;
+ }
+
/**
* Returns the base uri of the files root by removing
* the subpath from the URI
@@ -252,18 +258,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();
@@ -337,7 +334,7 @@ private function getSystemTagFileIds($systemTagIds) {
* @return Response[]
*/
public function prepareResponses($filesUri, $requestedProps, $nodes) {
- $responses = [];
+ $results = [];
foreach ($nodes as $node) {
$propFind = new PropFind($filesUri . $node->getPath(), $requestedProps);
@@ -346,18 +343,9 @@ public function prepareResponses($filesUri, $requestedProps, $nodes) {
$result = $propFind->getResultForMultiStatus();
$result['href'] = $propFind->getPath();
- $resourceType = $this->server->getResourceTypeForNode($node);
- if (in_array('{DAV:}collection', $resourceType) || in_array('{DAV:}principal', $resourceType)) {
- $result['href'] .= '/';
- }
-
- $responses[] = new Response(
- rtrim($this->server->getBaseUri(), '/') . $filesUri . $node->getPath(),
- $result,
- 200
- );
+ $results[] = $result;
}
- return $responses;
+ return $results;
}
/**
@@ -378,10 +366,9 @@ public function findNodesByFileIds($rootNode, $fileIds) {
$entry = $folder->getById($fileId);
if ($entry) {
$entry = current($entry);
- if ($entry instanceof \OCP\Files\File) {
- $results[] = new File($this->fileView, $entry);
- } else if ($entry instanceof \OCP\Files\Folder) {
- $results[] = new Directory($this->fileView, $entry);
+ $node = $this->makeSabreNode($entry);
+ if ($node) {
+ $results[] = $node;
}
}
}
@@ -389,6 +376,15 @@ public function findNodesByFileIds($rootNode, $fileIds) {
return $results;
}
+ private function makeSabreNode(\OCP\Files\Node $filesNode) {
+ if ($filesNode instanceof \OCP\Files\File) {
+ return new File($this->fileView, $filesNode);
+ } else if ($filesNode instanceof \OCP\Files\Folder) {
+ return new Directory($this->fileView, $filesNode);
+ }
+ throw new \Exception('Unrecognized Files API node returned, aborting');
+ }
+
/**
* Returns whether the currently logged in user is an administrator
*/
diff --git a/apps/dav/lib/Files/Xml/FilterRequest.php b/apps/dav/lib/Files/Xml/FilterRequest.php
new file mode 100644
index 000000000000..8cbc6f73ebbd
--- /dev/null
+++ b/apps/dav/lib/Files/Xml/FilterRequest.php
@@ -0,0 +1,110 @@
+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}search' => KeyValue::class,
+ ]);
+
+ $newProps = [
+ 'filters' => [
+ 'systemtag' => [],
+ 'favorite' => null
+ ],
+ 'properties' => [],
+ 'search' => 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}search' :
+ $value = $elem['value'];
+ if (isset($value['{http://owncloud.org/ns}pattern'])) {
+ $newProps['search']['pattern'] = $value['{http://owncloud.org/ns}pattern'];
+ }
+ if (isset($value['{http://owncloud.org/ns}limit'])) {
+ $newProps['search']['limit'] = (int)$value['{http://owncloud.org/ns}limit'];
+ }
+ if (isset($value['{http://owncloud.org/ns}offset'])) {
+ $newProps['search']['offset'] = (int)$value['{http://owncloud.org/ns}offset'];
+ }
+ 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 e9ee0d94546d..65036329bd85 100644
--- a/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php
+++ b/apps/dav/tests/unit/Connector/Sabre/FilesReportPluginTest.php
@@ -25,6 +25,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;
@@ -32,6 +33,8 @@
use OCP\SystemTag\ISystemTagManager;
use OCP\ITags;
use OCP\Files\FileInfo;
+use OCP\IRequest;
+use OCP\IConfig;
class FilesReportPluginTest extends \Test\TestCase {
/** @var \Sabre\DAV\Server|\PHPUnit_Framework_MockObject_MockObject */
@@ -70,13 +73,11 @@ public function setUp() {
->disableOriginalConstructor()
->getMock();
- $this->view = $this->getMockBuilder('\OC\Files\View')
- ->disableOriginalConstructor()
- ->getMock();
+ $this->view = new View();
$this->server = $this->getMockBuilder('\Sabre\DAV\Server')
->setConstructorArgs([$this->tree])
- ->setMethods(['getRequestUri', 'getBaseUri'])
+ ->setMethods(['getRequestUri', 'getBaseUri', 'generateMultiStatus'])
->getMock();
$this->server->expects($this->any())
@@ -109,6 +110,15 @@ public function setUp() {
->method('getUser')
->will($this->returnValue($user));
+ // add FilesPlugin to test more properties
+ $this->server->addPlugin(
+ new \OCA\DAV\Connector\Sabre\FilesPlugin(
+ $this->tree,
+ $this->createMock(IConfig::class),
+ $this->createMock(IRequest::class)
+ )
+ );
+
$this->plugin = new FilesReportPluginImplementation(
$this->tree,
$this->view,
@@ -156,21 +166,16 @@ 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',
+ '{http://owncloud.org/ns}fileid',
+ '{DAV:}resourcetype',
+ ];
+ $parameters->filters = [
+ 'systemtag' => [123, 456],
+ 'favorite' => null
];
$this->groupManager->expects($this->any())
@@ -186,14 +191,8 @@ public function testOnReport() {
->with('456', 'files')
->will($this->returnValue(['111', '222', '333']));
- $reportTargetNode = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory')
- ->disableOriginalConstructor()
- ->getMock();
-
- $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
- ->disableOriginalConstructor()
- ->getMock();
-
+ $reportTargetNode = $this->createMock(\OCA\DAV\Connector\Sabre\Directory::class);
+ $response = $this->createMock(\Sabre\HTTP\ResponseInterface::class);
$response->expects($this->once())
->method('setHeader')
->with('Content-Type', 'application/xml; charset=utf-8');
@@ -210,12 +209,16 @@ public function testOnReport() {
->with('/' . $path)
->will($this->returnValue($reportTargetNode));
- $filesNode1 = $this->getMockBuilder('\OCP\Files\Folder')
- ->disableOriginalConstructor()
- ->getMock();
- $filesNode2 = $this->getMockBuilder('\OCP\Files\File')
- ->disableOriginalConstructor()
- ->getMock();
+ $filesNode1 = $this->createMock(\OCP\Files\Folder::class);
+ $filesNode1->method('getId')->willReturn(111);
+ $filesNode1->method('getPath')->willReturn('/node1');
+ $filesNode1->method('isReadable')->willReturn(true);
+ $filesNode1->method('getSize')->willReturn(2048);
+ $filesNode2 = $this->createMock(\OCP\Files\File::class);
+ $filesNode2->method('getId')->willReturn(222);
+ $filesNode2->method('getPath')->willReturn('/sub/node2');
+ $filesNode2->method('getSize')->willReturn(1024);
+ $filesNode2->method('isReadable')->willReturn(true);
$this->userFolder->expects($this->at(0))
->method('getById')
@@ -232,7 +235,110 @@ public function testOnReport() {
$this->server->httpResponse = $response;
$this->plugin->initialize($this->server);
+ $responses = null;
+ $this->server->expects($this->once())
+ ->method('generateMultiStatus')
+ ->will($this->returnCallback(function($responsesArg) use (&$responses) {
+ $responses = $responsesArg;
+ })
+ );
+
$this->assertFalse($this->plugin->onReport(FilesReportPluginImplementation::REPORT_NAME, $parameters, '/' . $path));
+
+ $this->assertCount(2, $responses);
+
+ $this->assertTrue(isset($responses[0][200]));
+ $this->assertTrue(isset($responses[1][200]));
+
+ $this->assertEquals('/test/node1', $responses[0]['href']);
+ $this->assertEquals('/test/sub/node2', $responses[1]['href']);
+
+ $props1 = $responses[0];
+ $this->assertEquals('111', $props1[200]['{http://owncloud.org/ns}fileid']);
+ $this->assertNull($props1[404]['{DAV:}getcontentlength']);
+ $this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props1[200]['{DAV:}resourcetype']);
+ $resourceType1 = $props1[200]['{DAV:}resourcetype']->getValue();
+ $this->assertEquals('{DAV:}collection', $resourceType1[0]);
+
+ $props2 = $responses[1];
+ $this->assertEquals('1024', $props2[200]['{DAV:}getcontentlength']);
+ $this->assertEquals('222', $props2[200]['{http://owncloud.org/ns}fileid']);
+ $this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props2[200]['{DAV:}resourcetype']);
+ $this->assertCount(0, $props2[200]['{DAV:}resourcetype']->getValue());
+ }
+
+ public function testOnReportPaginationFiltered() {
+ $path = 'test';
+
+ $parameters = new FilterRequest();
+ $parameters->properties = [
+ '{DAV:}getcontentlength',
+ ];
+ $parameters->filters = [
+ 'systemtag' => [],
+ 'favorite' => true
+ ];
+ $parameters->search = [
+ 'offset' => 2,
+ 'limit' => 3,
+ ];
+
+ $filesNodes = [];
+ for ($i = 0; $i < 20; $i++) {
+ $filesNode = $this->createMock(\OCP\Files\File::class);
+ $filesNode->method('getId')->willReturn(1000 + $i);
+ $filesNode->method('getPath')->willReturn('/nodes/node' . $i);
+ $filesNode->method('isReadable')->willReturn(true);
+ $filesNodes[$filesNode->getId()] = $filesNode;
+ }
+
+ // return all above nodes as favorites
+ $this->privateTags->expects($this->once())
+ ->method('getFavorites')
+ ->will($this->returnValue(array_keys($filesNodes)));
+
+ $reportTargetNode = $this->createMock(\OCA\DAV\Connector\Sabre\Directory::class);
+
+ $this->tree->expects($this->any())
+ ->method('getNodeForPath')
+ ->with('/' . $path)
+ ->will($this->returnValue($reportTargetNode));
+
+ // getById must only be called for the required nodes
+ $this->userFolder->expects($this->at(0))
+ ->method('getById')
+ ->with(1002)
+ ->willReturn([$filesNodes[1002]]);
+ $this->userFolder->expects($this->at(1))
+ ->method('getById')
+ ->with(1003)
+ ->willReturn([$filesNodes[1003]]);
+ $this->userFolder->expects($this->at(2))
+ ->method('getById')
+ ->with(1004)
+ ->willReturn([$filesNodes[1004]]);
+
+ $this->server->expects($this->any())
+ ->method('getRequestUri')
+ ->will($this->returnValue($path));
+
+ $this->plugin->initialize($this->server);
+
+ $responses = null;
+ $this->server->expects($this->once())
+ ->method('generateMultiStatus')
+ ->will($this->returnCallback(function($responsesArg) use (&$responses) {
+ $responses = $responsesArg;
+ })
+ );
+
+ $this->assertFalse($this->plugin->onReport(FilesReportPluginImplementation::REPORT_NAME, $parameters, '/' . $path));
+
+ $this->assertCount(3, $responses);
+
+ $this->assertEquals('/test/nodes/node2', $responses[0]['href']);
+ $this->assertEquals('/test/nodes/node3', $responses[1]['href']);
+ $this->assertEquals('/test/nodes/node4', $responses[2]['href']);
}
public function testFindNodesByFileIdsRoot() {
@@ -327,71 +433,6 @@ public function testFindNodesByFileIdsSubDir() {
$this->assertEquals('second node', $result[1]->getName());
}
- public function testPrepareResponses() {
- $requestedProps = ['{DAV:}getcontentlength', '{http://owncloud.org/ns}fileid', '{DAV:}resourcetype'];
-
- $fileInfo = $this->createMock(FileInfo::class);
- $fileInfo->method('isReadable')->willReturn(true);
-
- $node1 = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory')
- ->disableOriginalConstructor()
- ->getMock();
- $node2 = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File')
- ->disableOriginalConstructor()
- ->getMock();
-
- $node1->expects($this->once())
- ->method('getInternalFileId')
- ->will($this->returnValue('111'));
- $node1->expects($this->any())
- ->method('getPath')
- ->will($this->returnValue('/node1'));
- $node1->method('getFileInfo')->willReturn($fileInfo);
- $node2->expects($this->once())
- ->method('getInternalFileId')
- ->will($this->returnValue('222'));
- $node2->expects($this->once())
- ->method('getSize')
- ->will($this->returnValue(1024));
- $node2->expects($this->any())
- ->method('getPath')
- ->will($this->returnValue('/sub/node2'));
- $node2->method('getFileInfo')->willReturn($fileInfo);
-
- $config = $this->createMock('\OCP\IConfig');
-
- $this->server->addPlugin(
- new \OCA\DAV\Connector\Sabre\FilesPlugin(
- $this->tree,
- $config,
- $this->createMock('\OCP\IRequest')
- )
- );
- $this->plugin->initialize($this->server);
- $responses = $this->plugin->prepareResponses('/files/username', $requestedProps, [$node1, $node2]);
-
- $this->assertCount(2, $responses);
-
- $this->assertEquals(200, $responses[0]->getHttpStatus());
- $this->assertEquals(200, $responses[1]->getHttpStatus());
-
- $this->assertEquals('http://example.com/owncloud/remote.php/dav/files/username/node1', $responses[0]->getHref());
- $this->assertEquals('http://example.com/owncloud/remote.php/dav/files/username/sub/node2', $responses[1]->getHref());
-
- $props1 = $responses[0]->getResponseProperties();
- $this->assertEquals('111', $props1[200]['{http://owncloud.org/ns}fileid']);
- $this->assertNull($props1[404]['{DAV:}getcontentlength']);
- $this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props1[200]['{DAV:}resourcetype']);
- $resourceType1 = $props1[200]['{DAV:}resourcetype']->getValue();
- $this->assertEquals('{DAV:}collection', $resourceType1[0]);
-
- $props2 = $responses[1]->getResponseProperties();
- $this->assertEquals('1024', $props2[200]['{DAV:}getcontentlength']);
- $this->assertEquals('222', $props2[200]['{http://owncloud.org/ns}fileid']);
- $this->assertInstanceOf('\Sabre\DAV\Xml\Property\ResourceType', $props2[200]['{DAV:}resourcetype']);
- $this->assertCount(0, $props2[200]['{DAV:}resourcetype']->getValue());
- }
-
public function testProcessFilterRulesSingle() {
$this->groupManager->expects($this->any())
->method('isAdmin')
@@ -407,7 +448,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]));
@@ -429,9 +471,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])));
@@ -454,8 +497,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])));
@@ -478,8 +521,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])));
@@ -504,9 +547,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])));
@@ -547,8 +589,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])));
@@ -584,8 +626,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]);
@@ -627,8 +669,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])));
@@ -636,7 +678,8 @@ public function testProcessFilterRulesVisibleTagAsUser() {
public function testProcessFavoriteFilter() {
$rules = [
- ['name' => '{http://owncloud.org/ns}favorite', 'value' => '1'],
+ 'systemtag' => [],
+ 'favorite' => true
];
$this->privateTags->expects($this->once())
diff --git a/tests/integration/features/bootstrap/WebDav.php b/tests/integration/features/bootstrap/WebDav.php
index b4c4e63a5184..db4bc3c75c42 100644
--- a/tests/integration/features/bootstrap/WebDav.php
+++ b/tests/integration/features/bootstrap/WebDav.php
@@ -392,18 +392,33 @@ public function listFolder($user, $path, $folderDepth, $properties = null){
* @param string $properties properties which needs to be included in the report
* @param string $filterRules filter-rules to choose what needs to appear in the report
*/
- public function reportFolder($user, $path, $properties, $filterRules){
+ public function reportFolder($user, $path, $properties, $filterRules, $offset = null, $limit = null){
$client = $this->getSabreClient($user);
$body = '
-
-
- ' . $properties . '
-
-
- ' . $filterRules . '
-
- ';
+
+
+ ' . $properties . '
+
+
+ ' . $filterRules . '
+ ';
+ if (is_int($offset) || is_int($limit)) {
+ $body .= '
+ ';
+ if (is_int($offset)) {
+ $body .= "
+ ${offset}";
+ }
+ if (is_int($limit)) {
+ $body .= "
+ ${limit}";
+ }
+ $body .= '
+ ';
+ }
+ $body .= '
+ ';
$response = $client->request('REPORT', $this->makeSabrePath($user, $path), $body);
$parsedResponse = $client->parseMultistatus($response['body']);
@@ -757,6 +772,18 @@ public function thereAreNoDuplicateHeaders() {
* @param \Behat\Gherkin\Node\TableNode|null $expectedElements
*/
public function checkFavoritedElements($user, $folder, $expectedElements){
+ $this->checkFavoritedElementsPaginated($user, $folder, $expectedElements, null, null);
+ }
+
+ /**
+ * @Then /^user "([^"]*)" in folder "([^"]*)" should have favorited the following elements from offset ([\d*]) and limit ([\d*])$/
+ * @param string $user
+ * @param string $folder
+ * @param \Behat\Gherkin\Node\TableNode|null $expectedElements
+ * @param int $offset
+ * @param int $limit
+ */
+ public function checkFavoritedElementsPaginated($user, $folder, $expectedElements, $offset, $limit){
$elementList = $this->reportFolder($user,
$folder,
'',
diff --git a/tests/integration/features/favorites.feature b/tests/integration/features/favorites.feature
index c2fdb1dfc118..9c15616fc3f9 100644
--- a/tests/integration/features/favorites.feature
+++ b/tests/integration/features/favorites.feature
@@ -147,3 +147,24 @@ Feature: favorite
Then user "user1" in folder "/" should have favorited the following elements
| /taken_out.txt |
+ Scenario: Get favorited elements paginated
+ Given using old dav path
+ And As an "admin"
+ And user "user0" exists
+ And user "user0" created a folder "/subfolder"
+ And User "user0" copies file "/textfile0.txt" to "/subfolder/textfile0.txt"
+ And User "user0" copies file "/textfile0.txt" to "/subfolder/textfile1.txt"
+ And User "user0" copies file "/textfile0.txt" to "/subfolder/textfile2.txt"
+ And User "user0" copies file "/textfile0.txt" to "/subfolder/textfile3.txt"
+ And User "user0" copies file "/textfile0.txt" to "/subfolder/textfile4.txt"
+ And User "user0" copies file "/textfile0.txt" to "/subfolder/textfile5.txt"
+ When user "user0" favorites element "/subfolder/textfile0.txt"
+ And user "user0" favorites element "/subfolder/textfile1.txt"
+ And user "user0" favorites element "/subfolder/textfile2.txt"
+ And user "user0" favorites element "/subfolder/textfile3.txt"
+ And user "user0" favorites element "/subfolder/textfile4.txt"
+ And user "user0" favorites element "/subfolder/textfile5.txt"
+ Then user "user0" in folder "/subfolder" should have favorited the following elements from offset 3 and limit 2
+ | /subfolder/textfile2.txt |
+ | /subfolder/textfile3.txt |
+