add icewind/searchdav

Signed-off-by: Robin Appelman <robin@icewind.nl>
This commit is contained in:
Robin Appelman 2017-02-02 18:19:16 +01:00
parent b5a6f03362
commit 706131b394
No known key found for this signature in database
GPG key ID: CBCA68FBAEBF98C9
13 changed files with 632 additions and 1 deletions

@ -1 +1 @@
Subproject commit 489bcf4f81e462f4d74f0b76f58caeabd58e75de
Subproject commit 2838fa6777b1427c6c912a5e599a96639ac2b31f

View file

@ -0,0 +1,76 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\DAV\Files;
use OCA\DAV\Connector\Sabre\Directory;
use Sabre\DAV\Exception\NotFound;
use Sabre\DAV\Tree;
use SearchDAV\Backend\ISearchBackend;
use SearchDAV\Backend\SearchPropertyDefinition;
class FileSearchBackend implements ISearchBackend {
/** @var Tree */
private $tree;
/**
* FileSearchBackend constructor.
*
* @param Tree $tree
*/
public function __construct(Tree $tree) {
$this->tree = $tree;
}
/**
* Search endpoint will be remote.php/dav/files
*
* @return string
*/
public function getArbiterPath() {
return 'files';
}
public function isValidScope($href, $depth, $path) {
// only allow scopes inside the dav server
if (is_null($path)) {
return false;
}
try {
$node = $this->tree->getNodeForPath($path);
return $node instanceof Directory;
} catch (NotFound $e) {
return false;
}
}
public function getPropertyDefinitionsForScope($href, $path) {
// all valid scopes support the same schema
return [
new SearchPropertyDefinition('{DAV:}getcontentlength', true, true, true, SearchPropertyDefinition::DATATYPE_NONNEGATIVE_INTEGER),
new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true),
new SearchPropertyDefinition('{DAV:}displayname', true, true, true),
new SearchPropertyDefinition('{http://ns.nextcloud.com:}fileid', false, true, true, SearchPropertyDefinition::DATATYPE_NONNEGATIVE_INTEGER),
];
}
}

View file

@ -0,0 +1,155 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\Files\Cache;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\IMimeTypeLoader;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchComparison;
use OCP\Files\Search\ISearchOperator;
/**
* Tools for transforming search queries into database queries
*/
class QuerySearchUtil {
static protected $searchOperatorMap = [
ISearchComparison::COMPARE_LIKE => 'iLike',
ISearchComparison::COMPARE_EQUAL => 'eq',
ISearchComparison::COMPARE_GREATER_THAN => 'gt',
ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'gte',
ISearchComparison::COMPARE_LESS_THAN => 'lt',
ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lte'
];
static protected $searchOperatorNegativeMap = [
ISearchComparison::COMPARE_LIKE => 'notLike',
ISearchComparison::COMPARE_EQUAL => 'neq',
ISearchComparison::COMPARE_GREATER_THAN => 'lte',
ISearchComparison::COMPARE_GREATER_THAN_EQUAL => 'lt',
ISearchComparison::COMPARE_LESS_THAN => 'gte',
ISearchComparison::COMPARE_LESS_THAN_EQUAL => 'lt'
];
/** @var IMimeTypeLoader */
private $mimetypeLoader;
/**
* QuerySearchUtil constructor.
*
* @param IMimeTypeLoader $mimetypeLoader
*/
public function __construct(IMimeTypeLoader $mimetypeLoader) {
$this->mimetypeLoader = $mimetypeLoader;
}
public function searchOperatorToDBExpr(IQueryBuilder $builder, ISearchOperator $operator) {
$expr = $builder->expr();
if ($operator instanceof ISearchBinaryOperator) {
switch ($operator->getType()) {
case ISearchBinaryOperator::OPERATOR_NOT:
$negativeOperator = $operator->getArguments()[0];
if ($negativeOperator instanceof ISearchComparison) {
return $this->searchComparisonToDBExpr($builder, $negativeOperator, self::$searchOperatorNegativeMap);
} else {
throw new \InvalidArgumentException('Binary operators inside "not" is not supported');
}
case ISearchBinaryOperator::OPERATOR_AND:
return $expr->andX($this->searchOperatorToDBExpr($operator->getArguments()[0], $operator->getArguments()[1]));
case ISearchBinaryOperator::OPERATOR_OR:
return $expr->orX($this->searchOperatorToDBExpr($operator->getArguments()[0], $operator->getArguments()[1]));
default:
throw new \InvalidArgumentException('Invalid operator type: ' . $operator->getType());
}
} else if ($operator instanceof ISearchComparison) {
return $this->searchComparisonToDBExpr($builder, $operator, self::$searchOperatorMap);
} else {
throw new \InvalidArgumentException('Invalid operator type: ' . get_class($operator));
}
}
private function searchComparisonToDBExpr(IQueryBuilder $builder, ISearchComparison $comparison, array $operatorMap) {
if (!$this->isValidComparison($comparison)) {
throw new \InvalidArgumentException('Invalid comparison ' . $operator->getType() . ' on field ' . $operator->getField());
}
list($field, $value) = $this->getOperatorFieldAndValue($comparison);
if (isset($operatorMap[$comparison->getType()])) {
$queryOperator = $operatorMap[$comparison->getType()];
return $builder->expr()->$queryOperator($field, $this->getParameterForValue($builder, $value));
} else {
throw new \InvalidArgumentException('Invalid operator type: ' . $comparison->getType());
}
}
private function getOperatorFieldAndValue(ISearchComparison $operator) {
$field = $operator->getField();
$value = $operator->getValue();
if ($field === 'mimetype') {
if ($operator->getType() === ISearchComparison::COMPARE_EQUAL) {
$value = $this->mimetypeLoader->getId($value);
} else if ($operator->getType() === ISearchComparison::COMPARE_LIKE) {
// transform "mimetype='foo/%'" to "mimepart='foo'"
if (preg_match('|(.+)/%|', $value, $matches)) {
$field = 'mimepart';
$value = $this->mimetypeLoader->getId($matches[1]);
}
}
}
return [$field, $value];
}
private function isValidComparison(ISearchComparison $operator) {
$types = [
'mimetype' => 'string',
'mtime' => \DateTime::class,
'name' => 'string',
'size' => 'integer'
];
$comparisons = [
'mimetype' => ['eq', 'like'],
'mtime' => ['eq', 'gt', 'lt', 'gte', 'lte'],
'name' => ['eq', 'like'],
'size' => ['eq', 'gt', 'lt', 'gte', 'lte']
];
if (!isset($types[$operator->getField()])) {
return false;
}
$type = $types[$operator->getField()];
if (gettype($operator->getValue()) !== $type && !(is_a($operator->getValue(), $type))) {
return false;
}
return in_array($operator->getType(), $comparisons[$operator->getField()]);
}
private function getParameterForValue(IQueryBuilder $builder, $value) {
if ($value instanceof \DateTime) {
$value = $value->getTimestamp();
}
if (is_numeric($value)) {
$type = IQueryBuilder::PARAM_INT;
} else {
$type = IQueryBuilder::PARAM_STR;
}
return $builder->createNamedParameter($value, $type);
}
}

View file

@ -0,0 +1,20 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

View file

@ -0,0 +1,67 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\Files\Search;
use OCP\Files\Search\ISearchComparison;
class SearchComparison implements ISearchComparison {
/** @var string */
private $type;
/** @var string */
private $field;
/** @var string|integer|\DateTime */
private $value;
/**
* SearchComparison constructor.
*
* @param string $type
* @param string $field
* @param \DateTime|int|string $value
*/
public function __construct($type, $field, $value) {
$this->type = $type;
$this->field = $field;
$this->value = $value;
}
/**
* @return string
*/
public function getType() {
return $this->type;
}
/**
* @return string
*/
public function getField() {
return $this->field;
}
/**
* @return \DateTime|int|string
*/
public function getValue() {
return $this->value;
}
}

View file

@ -0,0 +1,57 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\Files\Search;
use OCP\Files\Search\ISearchOrder;
class SearchOrder implements ISearchOrder {
/** @var string */
private $direction;
/** @var string */
private $field;
/**
* SearchOrder constructor.
*
* @param string $direction
* @param string $field
*/
public function __construct($direction, $field) {
$this->direction = $direction;
$this->field = $field;
}
/**
* @return string
*/
public function getDirection() {
return $this->direction;
}
/**
* @return string
*/
public function getField() {
return $this->field;
}
}

View file

@ -0,0 +1,23 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\Files\Search;

View file

@ -0,0 +1,46 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Files\Search;
interface ISearchBinaryOperator extends ISearchOperator {
const OPERATOR_AND = 'and';
const OPERATOR_OR = 'or';
const OPERATOR_NOT = 'not';
/**
* The type of binary operator
*
* One of the ISearchBinaryOperator::OPERATOR_* constants
*
* @return string
*/
public function getType();
/**
* The arguments for the binary operator
*
* One argument for the 'not' operator and two for 'and' and 'or'
*
* @return ISearchOperator[]
*/
public function getArguments();
}

View file

@ -0,0 +1,54 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Files\Search;
interface ISearchComparison extends ISearchOperator {
const COMPARE_EQUAL = 'eq';
const COMPARE_GREATER_THAN = 'gt';
const COMPARE_GREATER_THAN_EQUAL = 'gte';
const COMPARE_LESS_THAN = 'lt';
const COMPARE_LESS_THAN_EQUAL = 'lte';
const COMPARE_LIKE = 'like';
/**
* Get the type of comparison, one of the ISearchComparison::COMPARE_* constants
*
* @return string
*/
public function getType();
/**
* Get the name of the field to compare with
*
* i.e. 'size', 'name' or 'mimetype'
*
* @return string
*/
public function getField();
/**
* Get the value to compare the field with
*
* @return string|integer|\DateTime
*/
public function getValue();
}

View file

@ -0,0 +1,26 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Files\Search;
interface ISearchCondition {
}

View file

@ -0,0 +1,46 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Files\Search;
/**
* @since 12.0.0
*/
interface ISearchOrder {
const DIRECTION_ASCENDING = 'asc';
const DIRECTION_DESCENDING = 'desc';
/**
* The direction to sort in, either ISearchOrder::DIRECTION_ASCENDING or ISearchOrder::DIRECTION_DESCENDING
*
* @return string
* @since 12.0.0
*/
public function getDirection();
/**
* The field to sort on
*
* @return string
* @since 12.0.0
*/
public function getField();
}

View file

@ -0,0 +1,33 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCP\Files\Search;
/**
* @since 12.0.0
*/
interface ISearchQuery {
/**
* @return ISearchOperator
* @since 12.0.0
*/
public function getSearchOperation();
}

View file

@ -0,0 +1,28 @@
<?php
/**
* @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Test\Files\Cache;
use Test\TestCase;
class QuerySearchHelperTest extends TestCase {
}