diff options
author | Robin Appelman <robin@icewind.nl> | 2020-01-31 15:06:26 +0100 |
---|---|---|
committer | Roeland Jago Douma <roeland@famdouma.nl> | 2020-03-18 13:41:04 +0100 |
commit | ce398cf7bdfa1c4edeeee9b5259a415ef23031ac (patch) | |
tree | 3e2904a038c40a79e208c39f7c72e9632a257675 /apps/dav/lib/Connector | |
parent | ca54813cbb8f4c6ab6395ef921f3de3d4a834bb3 (diff) | |
download | nextcloud-server-ce398cf7bdfa1c4edeeee9b5259a415ef23031ac.tar.gz nextcloud-server-ce398cf7bdfa1c4edeeee9b5259a415ef23031ac.zip |
merge the two almost identical custom property backends
Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'apps/dav/lib/Connector')
-rw-r--r-- | apps/dav/lib/Connector/Sabre/CustomPropertiesBackend.php | 351 | ||||
-rw-r--r-- | apps/dav/lib/Connector/Sabre/ServerFactory.php | 2 |
2 files changed, 1 insertions, 352 deletions
diff --git a/apps/dav/lib/Connector/Sabre/CustomPropertiesBackend.php b/apps/dav/lib/Connector/Sabre/CustomPropertiesBackend.php deleted file mode 100644 index daa71dac070..00000000000 --- a/apps/dav/lib/Connector/Sabre/CustomPropertiesBackend.php +++ /dev/null @@ -1,351 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Aaron Wood <aaronjwood@gmail.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * @author Thomas Müller <thomas.mueller@tmit.eu> - * @author Vincent Petry <pvince81@owncloud.com> - * - * @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 OCP\IDBConnection; -use OCP\IUser; -use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\Exception\ServiceUnavailable; -use Sabre\DAV\PropertyStorage\Backend\BackendInterface; -use Sabre\DAV\PropFind; -use Sabre\DAV\PropPatch; -use Sabre\DAV\Tree; - -class CustomPropertiesBackend implements BackendInterface { - - /** - * Ignored properties - * - * @var array - */ - private $ignoredProperties = array( - '{DAV:}getcontentlength', - '{DAV:}getcontenttype', - '{DAV:}getetag', - '{DAV:}quota-used-bytes', - '{DAV:}quota-available-bytes', - '{http://owncloud.org/ns}permissions', - '{http://owncloud.org/ns}downloadURL', - '{http://owncloud.org/ns}dDC', - '{http://owncloud.org/ns}size', - '{http://nextcloud.org/ns}is-encrypted', - ); - - /** - * @var Tree - */ - private $tree; - - /** - * @var IDBConnection - */ - private $connection; - - /** - * @var IUser - */ - private $user; - - /** - * Properties cache - * - * @var array - */ - private $cache = []; - - /** - * @param Tree $tree node tree - * @param IDBConnection $connection database connection - * @param IUser $user owner of the tree and properties - */ - public function __construct( - Tree $tree, - IDBConnection $connection, - IUser $user) { - $this->tree = $tree; - $this->connection = $connection; - $this->user = $user->getUID(); - } - - /** - * Fetches properties for a path. - * - * @param string $path - * @param PropFind $propFind - * @return void - */ - public function propFind($path, PropFind $propFind) { - try { - $node = $this->tree->getNodeForPath($path); - if (!($node instanceof Node)) { - return; - } - } catch (ServiceUnavailable $e) { - // might happen for unavailable mount points, skip - return; - } catch (NotFound $e) { - // in some rare (buggy) cases the node might not be found, - // we catch the exception to prevent breaking the whole list with a 404 - // (soft fail) - \OC::$server->getLogger()->warning( - 'Could not get node for path: \"' . $path . '\" : ' . $e->getMessage(), - array('app' => 'files') - ); - return; - } - - $requestedProps = $propFind->get404Properties(); - - // these might appear - $requestedProps = array_diff( - $requestedProps, - $this->ignoredProperties - ); - - if (empty($requestedProps)) { - return; - } - - $props = $this->getProperties($node, $requestedProps); - foreach ($props as $propName => $propValue) { - $propFind->set($propName, $propValue); - } - } - - /** - * Updates properties for a path - * - * @param string $path - * @param PropPatch $propPatch - * - * @return void - */ - public function propPatch($path, PropPatch $propPatch) { - $node = $this->tree->getNodeForPath($path); - if (!($node instanceof Node)) { - return; - } - - $propPatch->handleRemaining(function($changedProps) use ($node) { - return $this->updateProperties($node, $changedProps); - }); - } - - /** - * This method is called after a node is deleted. - * - * @param string $path path of node for which to delete properties - */ - public function delete($path) { - $statement = $this->connection->prepare( - 'DELETE FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?' - ); - $statement->execute(array($this->user, '/' . $path)); - $statement->closeCursor(); - - unset($this->cache[$path]); - } - - /** - * This method is called after a successful MOVE - * - * @param string $source - * @param string $destination - * - * @return void - */ - public function move($source, $destination) { - $statement = $this->connection->prepare( - 'UPDATE `*PREFIX*properties` SET `propertypath` = ?' . - ' WHERE `userid` = ? AND `propertypath` = ?' - ); - $statement->execute(array('/' . $destination, $this->user, '/' . $source)); - $statement->closeCursor(); - } - - /** - * Returns a list of properties for this nodes.; - * @param Node $node - * @param array $requestedProperties requested properties or empty array for "all" - * @return array - * @note The properties list is a list of propertynames the client - * requested, encoded as xmlnamespace#tagName, for example: - * http://www.example.org/namespace#author If the array is empty, all - * properties should be returned - */ - private function getProperties(Node $node, array $requestedProperties) { - $path = $node->getPath(); - if (isset($this->cache[$path])) { - return $this->cache[$path]; - } - - // TODO: chunking if more than 1000 properties - $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?'; - - $whereValues = array($this->user, $path); - $whereTypes = array(null, null); - - if (!empty($requestedProperties)) { - // request only a subset - $sql .= ' AND `propertyname` in (?)'; - $whereValues[] = $requestedProperties; - $whereTypes[] = \Doctrine\DBAL\Connection::PARAM_STR_ARRAY; - } - - $result = $this->connection->executeQuery( - $sql, - $whereValues, - $whereTypes - ); - - $props = []; - while ($row = $result->fetch()) { - $props[$row['propertyname']] = $row['propertyvalue']; - } - - $result->closeCursor(); - - $this->cache[$path] = $props; - return $props; - } - - /** - * Update properties - * - * @param Node $node node for which to update properties - * @param array $properties array of properties to update - * - * @return bool - */ - private function updateProperties($node, $properties) { - $path = $node->getPath(); - - $deleteStatement = 'DELETE FROM `*PREFIX*properties`' . - ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'; - - $insertStatement = 'INSERT INTO `*PREFIX*properties`' . - ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)'; - - $updateStatement = 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' . - ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'; - - // TODO: use "insert or update" strategy ? - $existing = $this->getProperties($node, array()); - $this->connection->beginTransaction(); - foreach ($properties as $propertyName => $propertyValue) { - // If it was null, we need to delete the property - if (is_null($propertyValue)) { - if (array_key_exists($propertyName, $existing)) { - $this->connection->executeUpdate($deleteStatement, - array( - $this->user, - $path, - $propertyName - ) - ); - } - } else { - if (!array_key_exists($propertyName, $existing)) { - $this->connection->executeUpdate($insertStatement, - array( - $this->user, - $path, - $propertyName, - $propertyValue - ) - ); - } else { - $this->connection->executeUpdate($updateStatement, - array( - $propertyValue, - $this->user, - $path, - $propertyName - ) - ); - } - } - } - - $this->connection->commit(); - unset($this->cache[$path]); - - return true; - } - - /** - * Bulk load properties for directory children - * - * @param Directory $node - * @param array $requestedProperties requested properties - * - * @return void - */ - private function loadChildrenProperties(Directory $node, $requestedProperties) { - $path = $node->getPath(); - if (isset($this->cache[$path])) { - // we already loaded them at some point - return; - } - - $childNodes = $node->getChildren(); - // pre-fill cache - foreach ($childNodes as $childNode) { - $this->cache[$childNode->getPath()] = []; - } - - $sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` LIKE ?'; - $sql .= ' AND `propertyname` in (?) ORDER BY `propertypath`, `propertyname`'; - - $result = $this->connection->executeQuery( - $sql, - array($this->user, $this->connection->escapeLikeParameter(rtrim($path, '/')) . '/%', $requestedProperties), - array(null, null, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY) - ); - - $oldPath = null; - $props = []; - while ($row = $result->fetch()) { - $path = $row['propertypath']; - if ($oldPath !== $path) { - // save previously gathered props - $this->cache[$oldPath] = $props; - $oldPath = $path; - // prepare props for next path - $props = []; - } - $props[$row['propertyname']] = $row['propertyvalue']; - } - if (!is_null($oldPath)) { - // save props from last run - $this->cache[$oldPath] = $props; - } - - $result->closeCursor(); - } - -} diff --git a/apps/dav/lib/Connector/Sabre/ServerFactory.php b/apps/dav/lib/Connector/Sabre/ServerFactory.php index 595e3b734b5..9efd9ba7b56 100644 --- a/apps/dav/lib/Connector/Sabre/ServerFactory.php +++ b/apps/dav/lib/Connector/Sabre/ServerFactory.php @@ -195,7 +195,7 @@ class ServerFactory { // custom properties plugin must be the last one $server->addPlugin( new \Sabre\DAV\PropertyStorage\Plugin( - new \OCA\DAV\Connector\Sabre\CustomPropertiesBackend( + new \OCA\DAV\DAV\CustomPropertiesBackend( $objectTree, $this->databaseConnection, $this->userSession->getUser() |