Skip to content

Commit

Permalink
Merge pull request #31946 from owncloud/search_api_stable10
Browse files Browse the repository at this point in the history
[stable10] Search api stable10
  • Loading branch information
DeepDiver1975 authored Jul 18, 2018
2 parents 78f5b53 + a6cdab1 commit aee9303
Show file tree
Hide file tree
Showing 6 changed files with 620 additions and 1 deletion.
5 changes: 5 additions & 0 deletions apps/dav/lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ public function getCapabilities() {
return [
'dav' => [
'chunking' => '1.0',
'zsync' => '1.0',
'reports' => [
'search-files',
],
]
];
}
}

201 changes: 201 additions & 0 deletions apps/dav/lib/Connector/Sabre/FilesSearchReportPlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
<?php
/**
* @author Juan Pablo Villafañez <jvillafanez@solidgear.es>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OCA\DAV\Connector\Sabre;

use Sabre\DAV\Server as DavServer;
use Sabre\DAV\ServerPlugin;
use Sabre\DAV\PropFind;
use Sabre\DAV\Exception\BadRequest;
use Sabre\DAV\Exception\NotImplemented;
use OCA\DAV\Files\Xml\SearchRequest;
use OCP\ISearch;
use OC\Search\Result\File as FileResult;

class FilesSearchReportPlugin extends ServerPlugin {
// namespace
const NS_OWNCLOUD = 'http://owncloud.org/ns';
const REPORT_NAME = '{http://owncloud.org/ns}search-files';

/**
* Reference to main server object
*
* @var DavServer
*/
private $server;

/** @var ISearch */
private $searchService;

public function __construct(ISearch $searchService) {
$this->searchService = $searchService;
}

/**
* This initializes the plugin.
*
* This function is called by \Sabre\DAV\Server, after
* addPlugin is called.
*
* This method should set up the required event subscriptions.
*
* @param DavServer $server
* @return void
*/
public function initialize(DavServer $server) {
$server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc';

$server->xml->elementMap[self::REPORT_NAME] = SearchRequest::class;

$this->server = $server;
$this->server->on('report', [$this, 'onReport']);
}

/**
* Returns a list of reports this plugin supports.
*
* This will be used in the {DAV:}supported-report-set property.
*
* @param string $uri
* @return array
*/
public function getSupportedReportSet($uri) {
$reportTargetNode = $this->server->tree->getNodeForPath($uri);
if ($reportTargetNode instanceof Directory && $reportTargetNode->getPath() === '/') {
return [self::REPORT_NAME];
} else {
return [];
}
}

/**
* REPORT operations to look for files
*
* @param string $reportName
* @param mixed $report
* @param string $uri
* @return bool
* @throws BadRequest
* @throws NotImplemented
* @internal param $ [] $report
*/
public function onReport($reportName, $report, $uri) {
$reportTargetNode = $this->server->tree->getNodeForPath($uri);
if (!$reportTargetNode instanceof Directory ||
$reportName !== self::REPORT_NAME) {
return;
}

if ($reportTargetNode->getPath() !== '/') {
throw new NotImplemented('Search report only available in the root folder of the user');
}

$requestedProps = $report->properties;
$searchInfo = $report->searchInfo;

if (!isset($searchInfo['pattern'])) {
throw new BadRequest('Search pattern cannot be empty');
}

$limit = 30;
if (isset($searchInfo['limit'])) {
$limit = $searchInfo['limit'];
}

$searchResults = $this->searchService->searchPaged(
$searchInfo['pattern'],
['files'],
1,
$limit
);

$filesUri = $this->getFilesBaseUri($uri, $reportTargetNode->getPath());

$xml = $this->server->generateMultiStatus(
$this->getSearchResultIterator($filesUri, $searchResults, $requestedProps)
);
$this->server->httpResponse->setStatus(207);
$this->server->httpResponse->setHeader(
'Content-Type',
'application/xml; charset=utf-8'
);
$this->server->httpResponse->setBody($xml);

return false;
}

/**
* @param string $filesUri the base uri for this user's files directory,
* usually /files/username
* @param File[] $searchResults the results coming from the search service,
* within the files app
* @param array $requestedProps the list of requested webDAV properties
* @return \Generator a generator to traverse over the properties of the
* search result, suitable for server's multistatus response
*/
private function getSearchResultIterator($filesUri, $searchResults, $requestedProps) {
$paths = \array_map(function ($searchResult) use ($filesUri) {
return $filesUri . $searchResult->path;
}, $searchResults);

$nodes = $this->server->tree->getMultipleNodes($paths);

$propFindType = $requestedProps ? PropFind::NORMAL : PropFind::ALLPROPS;

foreach ($nodes as $path => $node) {
$propFind = new PropFind(
$path,
$requestedProps,
0,
$propFindType
);
$this->server->getPropertiesByNode($propFind, $node);

$result = $propFind->getResultForMultiStatus();
$result['href'] = $propFind->getPath();
yield $result;
}
}

/**
* Returns the base uri of the files root by removing
* the subpath from the URI
*
* @param string $uri URI from this request
* @param string $subPath subpath to remove from the URI
*
* @return string files base uri
*/
private function getFilesBaseUri($uri, $subPath) {
$uri = \trim($uri, '/');
$subPath = \trim($subPath, '/');
if ($subPath === '') {
$filesUri = $uri;
} else {
$filesUri = \substr($uri, 0, \strlen($uri) - \strlen($subPath));
}
$filesUri = \trim($filesUri, '/');
if ($filesUri === '') {
return '';
}
return '/' . $filesUri;
}
}
5 changes: 5 additions & 0 deletions apps/dav/lib/Connector/Sabre/ServerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ public function createServer($baseUri,
\OC::$server->getGroupManager(),
$userFolder
));
$server->addPlugin(
new \OCA\DAV\Connector\Sabre\FilesSearchReportPlugin(
\OC::$server->getSearch()
)
);

// custom properties plugin must be the last one
$server->addPlugin(
Expand Down
81 changes: 81 additions & 0 deletions apps/dav/lib/Files/Xml/SearchRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php
/**
* @author Juan Pablo Villafañez <jvillafanez@solidgear.es>
*
* @copyright Copyright (c) 2018, ownCloud GmbH
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OCA\DAV\Files\Xml;

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

class SearchRequest implements XmlDeserializable {
/**
* An array with requested properties.
*
* @var array
*/
public $properties;

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

public static function xmlDeserialize(Reader $reader) {
$newProps = [
'properties' => [],
'searchInfo' => null,
];

$elems = (array)$reader->parseInnerTree([
'{DAV:}prop' => KeyValue::class,
'{http://owncloud.org/ns}search' => KeyValue::class,
]);

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}search':
$value = $elem['value'];
if (isset($value['{http://owncloud.org/ns}pattern'])) {
$newProps['searchInfo']['pattern'] = $value['{http://owncloud.org/ns}pattern'];
}
if (isset($value['{http://owncloud.org/ns}limit'])) {
$newProps['searchInfo']['limit'] = (int)$value['{http://owncloud.org/ns}limit'];
}
break;
}
}

$obj = new self();
foreach ($newProps as $key => $value) {
$obj->$key = $value;
}

return $obj;
}
}
8 changes: 7 additions & 1 deletion apps/dav/lib/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ public function __construct(IRequest $request, $baseUri) {
\OC::$server->getCommentsManager(),
$userSession
));
if (!is_null($view)) {

if ($view !== null) {
$this->server->addPlugin(new FilesReportPlugin(
$this->server->tree,
$view,
Expand All @@ -262,6 +263,11 @@ public function __construct(IRequest $request, $baseUri) {
$userFolder
));
}
$this->server->addPlugin(
new \OCA\DAV\Connector\Sabre\FilesSearchReportPlugin(
\OC::$server->getSearch()
)
);
}

// register plugins from apps
Expand Down
Loading

0 comments on commit aee9303

Please sign in to comment.