Skip to content

Commit

Permalink
Introduce pagination in files-filter report
Browse files Browse the repository at this point in the history
  • Loading branch information
DeepDiver1975 committed Oct 28, 2016
1 parent 8e9545d commit d67ffa0
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 38 deletions.
63 changes: 25 additions & 38 deletions apps/dav/lib/Connector/Sabre/FilesReportPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
namespace OCA\DAV\Connector\Sabre;

use OC\Files\View;
use OCA\DAV\Files\Xml\FilterRequest;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\Exception\PreconditionFailed;
use Sabre\DAV\Exception\ReportNotSupported;
Expand Down Expand Up @@ -140,6 +141,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']);
}
Expand All @@ -160,50 +163,43 @@ public function getSupportedReportSet($uri) {
* REPORT operations to look for files
*
* @param string $reportName
* @param [] $report
* @param mixed $report
* @param string $uri
* @return bool
* @throws NotFound
* @throws ReportNotSupported
*/
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);

Expand Down Expand Up @@ -253,18 +249,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();
Expand Down
104 changes: 104 additions & 0 deletions apps/dav/lib/Files/Xml/FilterRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace OCA\DAV\Files\Xml;

use Sabre\Xml\Element\Base;
use Sabre\Xml\Element\KeyValue;
use Sabre\Xml\Reader;
use Sabre\Xml\XmlDeserializable;

class FilterRequest implements XmlDeserializable {

/**
* An array with requested properties.
*
* @var array
*/
public $properties;

/**
* @var array
*/
public $filters;

/**
* @var array
*/
public $limit;

/**
* The deserialize method is called during xml parsing.
*
* This method is called statically, this is because in theory this method
* may be used as a type of constructor, or factory method.
*
* Often you want to return an instance of the current class, but you are
* free to return other data as well.
*
* You are responsible for advancing the reader to the next element. Not
* doing anything will result in a never-ending loop.
*
* If you just want to skip parsing for this element altogether, you can
* just call $reader->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;
}
}

0 comments on commit d67ffa0

Please sign in to comment.