From cc72c6a30dc12b49dec907cd2fcd01766dbda4c1 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 27 Nov 2015 12:54:31 +0100 Subject: [PATCH 1/4] Added dav endpoints for system tags --- apps/dav/lib/rootcollection.php | 9 + apps/dav/lib/server.php | 3 + .../lib/systemtag/systemtagmappingnode.php | 81 ++++++ apps/dav/lib/systemtag/systemtagnode.php | 112 ++++++++ apps/dav/lib/systemtag/systemtagplugin.php | 241 ++++++++++++++++++ .../systemtag/systemtagsbyidcollection.php | 119 +++++++++ .../systemtagsobjectmappingcollection.php | 160 ++++++++++++ .../systemtagsobjecttypecollection.php | 114 +++++++++ .../systemtagsrelationscollection.php | 50 ++++ .../systemtag/systemtagobjectmapper.php | 4 + 10 files changed, 893 insertions(+) create mode 100644 apps/dav/lib/systemtag/systemtagmappingnode.php create mode 100644 apps/dav/lib/systemtag/systemtagnode.php create mode 100644 apps/dav/lib/systemtag/systemtagplugin.php create mode 100644 apps/dav/lib/systemtag/systemtagsbyidcollection.php create mode 100644 apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php create mode 100644 apps/dav/lib/systemtag/systemtagsobjecttypecollection.php create mode 100644 apps/dav/lib/systemtag/systemtagsrelationscollection.php diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php index c1635c9cde..9ee32822bb 100644 --- a/apps/dav/lib/rootcollection.php +++ b/apps/dav/lib/rootcollection.php @@ -33,6 +33,13 @@ class RootCollection extends SimpleCollection { $caldavBackend = new CalDavBackend($db); $calendarRoot = new CalendarRoot($principalBackend, $caldavBackend, 'principals/users'); $calendarRoot->disableListing = $disableListing; + $systemTagCollection = new SystemTag\SystemTagsByIdCollection( + \OC::$server->getSystemTagManager() + ); + $systemTagRelationsCollection = new SystemTag\SystemTagsRelationsCollection( + \OC::$server->getSystemTagManager(), + \OC::$server->getSystemTagObjectMapper() + ); $usersCardDavBackend = new CardDavBackend($db, $principalBackend); $usersAddressBookRoot = new AddressBookRoot($principalBackend, $usersCardDavBackend, 'principals/users'); @@ -51,6 +58,8 @@ class RootCollection extends SimpleCollection { new SimpleCollection('addressbooks', [ $usersAddressBookRoot, $systemAddressBookRoot]), + $systemTagCollection, + $systemTagRelationsCollection, ]; parent::__construct('root', $children); diff --git a/apps/dav/lib/server.php b/apps/dav/lib/server.php index a031f2c442..ffcbb02db7 100644 --- a/apps/dav/lib/server.php +++ b/apps/dav/lib/server.php @@ -60,6 +60,9 @@ class Server { // addressbook plugins $this->server->addPlugin(new \OCA\DAV\CardDAV\Plugin()); + // system tags plugins + $this->server->addPlugin(new \OCA\DAV\SystemTag\SystemTagPlugin(\OC::$server->getSystemTagManager())); + // Finder on OS X requires Class 2 WebDAV support (locking), since we do // not provide locking we emulate it using a fake locking plugin. if($request->isUserAgent(['/WebDAVFS/'])) { diff --git a/apps/dav/lib/systemtag/systemtagmappingnode.php b/apps/dav/lib/systemtag/systemtagmappingnode.php new file mode 100644 index 0000000000..97c1afc140 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagmappingnode.php @@ -0,0 +1,81 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; + +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use OCP\SystemTag\TagNotFoundException; + +/** + * Mapping node for system tag to object id + */ +class SystemTagMappingNode extends SystemTagNode { + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * @var string + */ + private $objectId; + + /** + * @var string + */ + private $objectType; + + /** + * Sets up the node, expects a full path name + * + * @param ISystemTag $tag system tag + */ + public function __construct( + ISystemTag $tag, + $objectId, + $objectType, + ISystemTagManager $tagManager, + ISystemTagObjectMapper $tagMapper + ) { + $this->objectId = $objectId; + $this->objectType = $objectType; + $this->tagMapper = $tagMapper; + parent::__construct($tag, $tagManager); + } + + /** + * Delete tag to object association + */ + public function delete() { + try { + $this->tagMapper->unassignTags($this->objectId, $this->objectType, $this->tag->getId()); + } catch (TagNotFoundException $e) { + // can happen if concurrent deletion occurred + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e); + } + } +} diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php new file mode 100644 index 0000000000..e425595352 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -0,0 +1,112 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\Conflict; + +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\TagNotFoundException; + +class SystemTagNode implements \Sabre\DAV\INode { + + /** + * @var ISystemTag + */ + protected $tag; + + /** + * @var ISystemTagManager + */ + protected $tagManager; + + /** + * Sets up the node, expects a full path name + * + * @param ISystemTag $tag system tag + */ + public function __construct(ISystemTag $tag, ISystemTagManager $tagManager) { + $this->tag = $tag; + $this->tagManager = $tagManager; + } + + /** + * Returns the id of the tag + * + * @return string + */ + public function getName() { + return $this->tag->getId(); + } + + /** + * Returns the system tag represented by this node + * + * @return ISystemTag system tag + */ + public function getSystemTag() { + return $this->tag; + } + + /** + * Renames the node + * + * @param string $name The new name + * + * @throws \Sabre\DAV\Exception\MethodNotAllowed + */ + public function setName($name) { + throw new MethodNotAllowed(); + } + + /** + * @param string $name new tag name + * @param bool $userVisible user visible + * @param bool $userAssignable user assignable + */ + public function update($name, $userVisible, $userAssignable) { + try { + $this->tagManager->updateTag($name, $userVisible, $userAssignable); + } catch (TagAlreadyExistsException $e) { + throw new Conflict('Tag with the properties "' . $name . '", ' . $userVisible, ', ' . $userAssignable . ' already exists'); + } + } + + /** + * Returns null, not supported + * + */ + public function getLastModified() { + return null; + } + + public function delete() { + try { + $this->tagManager->deleteTags($this->tag->getId()); + } catch (TagNotFoundException $e) { + // can happen if concurrent deletion occurred + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e); + } + } +} diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php new file mode 100644 index 0000000000..c213640964 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagplugin.php @@ -0,0 +1,241 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @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 + * + */ +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\PropFind; +use Sabre\DAV\PropPatch; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Exception\UnsupportedMediaType; +use Sabre\DAV\Exception\Conflict; + +use OCA\DAV\SystemTag\SystemTagNode; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { + + // namespace + const NS_OWNCLOUD = 'http://owncloud.org/ns'; + const ID_PROPERTYNAME = '{http://owncloud.org/ns}id'; + const DISPLAYNAME_PROPERTYNAME = '{http://owncloud.org/ns}display-name'; + const USERVISIBLE_PROPERTYNAME = '{http://owncloud.org/ns}user-visible'; + const USERASSIGNABLE_PROPERTYNAME = '{http://owncloud.org/ns}user-assignable'; + + /** + * @var \Sabre\DAV\Server $server + */ + private $server; + + /** + * @var ISystemTagManager + */ + protected $tagManager; + + /** + * System tags plugin + * + * @param ISystemTagManager $tagManager tag manager + */ + public function __construct(ISystemTagManager $tagManager) { + $this->tagManager = $tagManager; + } + + /** + * 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 \Sabre\DAV\Server $server + * @return void + */ + public function initialize(\Sabre\DAV\Server $server) { + + $server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc'; + + $server->protectedProperties[] = self::ID_PROPERTYNAME; + + $server->on('propFind', array($this, 'handleGetProperties')); + $server->on('propPatch', array($this, 'handleUpdateProperties')); + $server->on('method:POST', [$this, 'httpPost']); + + $this->server = $server; + } + + /** + * We intercept this to handle POST requests on calendars. + * + * @param RequestInterface $request + * @param ResponseInterface $response + * @return null|false + */ + function httpPost(RequestInterface $request, ResponseInterface $response) { + $path = $request->getPath(); + + // Making sure the node exists + try { + $node = $this->server->tree->getNodeForPath($path); + } catch (NotFound $e) { + return; + } + + if ($node instanceof SystemTagsByIdCollection || $node instanceof SystemTagsObjectMappingCollection) { + $data = $request->getBodyAsString(); + + $tag = $this->createTag($data, $request->getHeader('Content-Type')); + + if ($node instanceof SystemTagsObjectMappingCollection) { + // also add to collection + $node->createFile($tag->getId()); + $url = $request->getBaseUrl() . 'systemtags/'; + } else { + $url = $request->getUrl(); + } + + if ($url[strlen($url) - 1] !== '/') { + $url .= '/'; + } + + $response->setHeader('Location', $url . $tag->getId()); + + // created + $response->setStatus(201); + return false; + } + } + + /** + * Creates a new tag + * + * @param string $data + * @param string $contentType content type of the data + * + * @return ISystemTag newly created system tag + * + * @throws UnsupportedMediaType if the content type is not supported + * @throws BadRequest if a field was missing + */ + private function createTag($data, $contentType = 'application/json') { + if ($contentType === 'application/json') { + $data = json_decode($data, true); + // TODO: application/x-www-form-urlencoded ? + } else { + throw new UnsupportedMediaType(); + } + + if (!isset($data['name'])) { + throw new BadRequest('Missing "name" attribute'); + } + + $tagName = $data['name']; + $userVisible = true; + $userAssignable = true; + + if (isset($data['userVisible'])) { + $userVisible = (bool)$data['userVisible']; + } + + if (isset($data['userAssignable'])) { + $userVisible = (bool)$data['userAssignable']; + } + try { + return $this->tagManager->createTag($tagName, $userVisible, $userAssignable); + } catch (TagAlreadyExistsException $e) { + throw new Conflict('Tag already exists'); + } + } + + + /** + * Retrieves system tag properties + * + * @param PropFind $propFind + * @param \Sabre\DAV\INode $node + */ + public function handleGetProperties( + PropFind $propFind, + \Sabre\DAV\INode $node + ) { + if (!($node instanceof SystemTagNode)) { + return; + } + + $propFind->handle(self::ID_PROPERTYNAME, function() use ($node) { + return $node->getSystemTag()->getId(); + }); + + $propFind->handle(self::DISPLAYNAME_PROPERTYNAME, function() use ($node) { + return $node->getSystemTag()->getName(); + }); + + $propFind->handle(self::USERVISIBLE_PROPERTYNAME, function() use ($node) { + return (int)$node->getSystemTag()->isUserVisible(); + }); + + $propFind->handle(self::USERASSIGNABLE_PROPERTYNAME, function() use ($node) { + return (int)$node->getSystemTag()->isUserAssignable(); + }); + } + + /** + * Updates tag attributes + * + * @param string $path + * @param PropPatch $propPatch + * + * @return void + */ + public function handleUpdateProperties($path, PropPatch $propPatch) { + $propPatch->handle([ + self::DISPLAYNAME_PROPERTYNAME, + self::USERVISIBLE_PROPERTYNAME, + self::USERASSIGNABLE_PROPERTYNAME, + ], function($props) use ($path) { + $node = $this->tree->getNodeForPath($path); + if (!($node instanceof SystemTagNode)) { + return; + } + + $tag = $node->getTag(); + $name = $tag->getName(); + $userVisible = $tag->getUserVisible(); + $userAssignable = $tag->getUserAssignable(); + + if (isset($props[self::DISPLAYNAME_PROPERTYNAME])) { + $name = $props[self::DISPLAYNAME_PROPERTYNAME]; + } + + if (isset($props[self::USERVISIBLE_PROPERTYNAME])) { + $userVisible = (bool)$props[self::USERVISIBLE_PROPERTYNAME]; + } + + if (isset($props[self::USERASSIGNABLE_PROPERTYNAME])) { + $userAssignable = (bool)$props[self::USERASSIGNABLE_PROPERTYNAME]; + } + + $node->update($name, $userVisible, $userAssignable); + return true; + }); + } +} diff --git a/apps/dav/lib/systemtag/systemtagsbyidcollection.php b/apps/dav/lib/systemtag/systemtagsbyidcollection.php new file mode 100644 index 0000000000..8643ffedd4 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsbyidcollection.php @@ -0,0 +1,119 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\ICollection; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\TagNotFoundException; +use OC\SystemTag\SystemTag; + +class SystemTagsByIdCollection implements ICollection { + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * SystemTagsByIdCollection constructor. + * + * @param ISystemTagManager $tagManager + */ + public function __construct($tagManager) { + $this->tagManager = $tagManager; + } + + function createFile($name, $data = null) { + throw new Forbidden('Cannot create tags by id'); + } + + function createDirectory($name) { + throw new Forbidden('Permission denied to create collections'); + } + + function getChild($name) { + try { + $tags = $this->tagManager->getTagsById($name); + return $this->makeNode(current($tags)); + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $name . ' not found', 0, $e); + } + } + + function getChildren() { + // TODO: set visibility filter based on principal/permissions ? + $tags = $this->tagManager->getAllTags(true); + return array_map(function($tag) { + return $this->makeNode($tag); + }, $tags); + } + + function childExists($name) { + try { + $this->tagManager->getTagsById($name); + return true; + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + return false; + } + } + + function delete() { + throw new Forbidden('Permission denied to delete this collection'); + } + + function getName() { + return 'systemtags'; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + function getLastModified() { + return null; + } + + /** + * Create a sabre node for the given system tag + * + * @param ISystemTag $tag + * + * @return SystemTagNode + */ + private function makeNode(ISystemTag $tag) { + return new SystemTagNode($tag, $this->tagManager); + } +} diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php new file mode 100644 index 0000000000..a0a71306f9 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -0,0 +1,160 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\ICollection; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\TagNotFoundException; +use OC\SystemTag\SystemTag; + +/** + * Collection containing tags by object id + */ +class SystemTagsObjectMappingCollection implements ICollection { + + /** + * @var string + */ + private $objectId; + + /** + * @var string + */ + private $objectType; + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * Constructor + * + * @param string $objectId object id + * @param string $objectType object type + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct($objectId, $objectType, $tagManager, $tagMapper) { + $this->tagManager = $tagManager; + $this->tagMapper = $tagMapper; + $this->objectId = $objectId; + $this->objectType = $objectType; + } + + function createFile($tagId, $data = null) { + try { + $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId); + } catch (TagNotFoundException $e) { + throw new Forbidden('Tag with id ' . $tagId . ' does not exist, cannot assign'); + } + } + + function createDirectory($name) { + throw new Forbidden('Permission denied to create collections'); + } + + function getChild($tagId) { + try { + if ($this->tagMapper->haveTag($this->objectId, $this->objectType, $tagId, true)) { + $tag = $this->tagManager->getTagsById($tagId); + return $this->makeNode(current($tag)); + } + throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId); + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e); + } + } + + function getChildren() { + $tagIds = current($this->tagMapper->getTagIdsForObjects($this->objectId, $this->objectType)); + if (empty($tagIds)) { + return []; + } + $tags = $this->tagManager->getTagsById($tagIds); + return array_map(function($tag) { + return $this->makeNode($tag); + }, $tags); + } + + function childExists($tagId) { + try { + return ($this->tagMapper->haveTag($this->objectId, $this->objectType, $tagId, true)); + } catch (\InvalidArgumentException $e) { + throw new BadRequest('Invalid tag id', 0, $e); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e); + } + } + + function delete() { + throw new Forbidden('Permission denied to delete this collection'); + } + + function getName() { + return $this->objectId; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + function getLastModified() { + return null; + } + + /** + * Create a sabre node for the given system tag + * + * @param ISystemTag $tag + * + * @return SystemTagNode + */ + private function makeNode(ISystemTag $tag) { + return new SystemTagMappingNode( + $tag, + $this->objectId, + $this->objectType, + $this->tagManager, + $this->tagMapper + ); + } +} diff --git a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php new file mode 100644 index 0000000000..c90e4fd2d8 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php @@ -0,0 +1,114 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\Exception\Forbidden; +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\ICollection; + +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use OCP\SystemTag\ISystemTag; +use OCP\SystemTag\TagNotFoundException; +use OC\SystemTag\SystemTag; + +/** + * Collection containing object ids by object type + */ +class SystemTagsObjectTypeCollection implements ICollection { + + /** + * @var string + */ + private $objectType; + + /** + * @var ISystemTagManager + */ + private $tagManager; + + /** + * @var ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * Constructor + * + * @param string $objectType object type + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct($objectType, $tagManager, $tagMapper) { + $this->tagManager = $tagManager; + $this->tagMapper = $tagMapper; + $this->objectType = $objectType; + } + + function createFile($name, $data = null) { + throw new Forbidden('Permission denied to create collections'); + } + + function createDirectory($name) { + throw new Forbidden('Permission denied to create collections'); + } + + function getChild($objectId) { + return new SystemTagsObjectMappingCollection( + $objectId, + $this->objectType, + $this->tagManager, + $this->tagMapper + ); + } + + function getChildren() { + // do not list object ids + throw new MethodNotAllowed(); + } + + function childExists($name) { + return true; + } + + function delete() { + throw new Forbidden('Permission denied to delete this collection'); + } + + function getName() { + return $this->objectType; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + function getLastModified() { + return null; + } +} diff --git a/apps/dav/lib/systemtag/systemtagsrelationscollection.php b/apps/dav/lib/systemtag/systemtagsrelationscollection.php new file mode 100644 index 0000000000..4bcb6882a4 --- /dev/null +++ b/apps/dav/lib/systemtag/systemtagsrelationscollection.php @@ -0,0 +1,50 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @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 + * + */ + +namespace OCA\DAV\SystemTag; + +use Sabre\DAV\SimpleCollection; + +class SystemTagsRelationsCollection extends SimpleCollection { + + /** + * SystemTagsRelationsCollection constructor. + * + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper + */ + public function __construct($tagManager, $tagMapper) { + $children = [ + new SystemTagsObjectTypeCollection('files', $tagManager, $tagMapper), + ]; + + parent::__construct('root', $children); + } + + function getName() { + return 'systemtags-relations'; + } + + function setName($name) { + throw new Forbidden('Permission denied to rename this collection'); + } + +} diff --git a/lib/private/systemtag/systemtagobjectmapper.php b/lib/private/systemtag/systemtagobjectmapper.php index 75f2631a01..bb64a35456 100644 --- a/lib/private/systemtag/systemtagobjectmapper.php +++ b/lib/private/systemtag/systemtagobjectmapper.php @@ -171,6 +171,10 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { public function haveTag($objIds, $objectType, $tagId, $all = true) { $this->assertTagsExist([$tagId]); + if (!is_array($objIds)) { + $objIds = [$objIds]; + } + $query = $this->connection->getQueryBuilder(); if (!$all) { From 502e454a6902c51d6756d606061a1a9092946c8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Wed, 2 Dec 2015 21:17:03 +0100 Subject: [PATCH 2/4] Fix PHPDoc ... --- .../dav/lib/systemtag/systemtagmappingnode.php | 5 ++++- apps/dav/lib/systemtag/systemtagnode.php | 3 +++ apps/dav/lib/systemtag/systemtagplugin.php | 18 ++++++++++-------- .../lib/systemtag/systemtagsbyidcollection.php | 1 - .../systemtagsobjectmappingcollection.php | 2 -- .../systemtagsobjecttypecollection.php | 4 ---- .../systemtagsrelationscollection.php | 3 +++ 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/apps/dav/lib/systemtag/systemtagmappingnode.php b/apps/dav/lib/systemtag/systemtagmappingnode.php index 97c1afc140..03088d734d 100644 --- a/apps/dav/lib/systemtag/systemtagmappingnode.php +++ b/apps/dav/lib/systemtag/systemtagmappingnode.php @@ -22,7 +22,6 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\Exception\MethodNotAllowed; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; @@ -53,6 +52,10 @@ class SystemTagMappingNode extends SystemTagNode { * Sets up the node, expects a full path name * * @param ISystemTag $tag system tag + * @param string $objectId + * @param string $objectType + * @param ISystemTagManager $tagManager + * @param ISystemTagObjectMapper $tagMapper */ public function __construct( ISystemTag $tag, diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php index e425595352..b09a773793 100644 --- a/apps/dav/lib/systemtag/systemtagnode.php +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -21,6 +21,7 @@ namespace OCA\DAV\SystemTag; +use OCP\SystemTag\TagAlreadyExistsException; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\Exception\Conflict; @@ -45,6 +46,7 @@ class SystemTagNode implements \Sabre\DAV\INode { * Sets up the node, expects a full path name * * @param ISystemTag $tag system tag + * @param ISystemTagManager $tagManager */ public function __construct(ISystemTag $tag, ISystemTagManager $tagManager) { $this->tag = $tag; @@ -84,6 +86,7 @@ class SystemTagNode implements \Sabre\DAV\INode { * @param string $name new tag name * @param bool $userVisible user visible * @param bool $userAssignable user assignable + * @throws Conflict */ public function update($name, $userVisible, $userAssignable) { try { diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php index c213640964..d5591c2849 100644 --- a/apps/dav/lib/systemtag/systemtagplugin.php +++ b/apps/dav/lib/systemtag/systemtagplugin.php @@ -20,16 +20,18 @@ */ namespace OCA\DAV\SystemTag; +use Sabre\DAV\Exception\NotFound; use Sabre\DAV\PropFind; use Sabre\DAV\PropPatch; use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\Exception\UnsupportedMediaType; use Sabre\DAV\Exception\Conflict; -use OCA\DAV\SystemTag\SystemTagNode; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\TagAlreadyExistsException; +use Sabre\HTTP\RequestInterface; +use Sabre\HTTP\ResponseInterface; class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { @@ -72,7 +74,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { */ public function initialize(\Sabre\DAV\Server $server) { - $server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc'; + $server->xml->namespaceMap[self::NS_OWNCLOUD] = 'oc'; $server->protectedProperties[] = self::ID_PROPERTYNAME; @@ -130,11 +132,11 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { * * @param string $data * @param string $contentType content type of the data - * * @return ISystemTag newly created system tag * - * @throws UnsupportedMediaType if the content type is not supported * @throws BadRequest if a field was missing + * @throws Conflict + * @throws UnsupportedMediaType if the content type is not supported */ private function createTag($data, $contentType = 'application/json') { if ($contentType === 'application/json') { @@ -212,15 +214,15 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { self::USERVISIBLE_PROPERTYNAME, self::USERASSIGNABLE_PROPERTYNAME, ], function($props) use ($path) { - $node = $this->tree->getNodeForPath($path); + $node = $this->server->tree->getNodeForPath($path); if (!($node instanceof SystemTagNode)) { return; } - $tag = $node->getTag(); + $tag = $node->getSystemTag(); $name = $tag->getName(); - $userVisible = $tag->getUserVisible(); - $userAssignable = $tag->getUserAssignable(); + $userVisible = $tag->isUserVisible(); + $userAssignable = $tag->isUserAssignable(); if (isset($props[self::DISPLAYNAME_PROPERTYNAME])) { $name = $props[self::DISPLAYNAME_PROPERTYNAME]; diff --git a/apps/dav/lib/systemtag/systemtagsbyidcollection.php b/apps/dav/lib/systemtag/systemtagsbyidcollection.php index 8643ffedd4..0164b9b0b3 100644 --- a/apps/dav/lib/systemtag/systemtagsbyidcollection.php +++ b/apps/dav/lib/systemtag/systemtagsbyidcollection.php @@ -29,7 +29,6 @@ use Sabre\DAV\ICollection; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\TagNotFoundException; -use OC\SystemTag\SystemTag; class SystemTagsByIdCollection implements ICollection { diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php index a0a71306f9..6ed959fd88 100644 --- a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -23,7 +23,6 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; -use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\Exception\BadRequest; use Sabre\DAV\ICollection; @@ -31,7 +30,6 @@ use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagObjectMapper; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\TagNotFoundException; -use OC\SystemTag\SystemTag; /** * Collection containing tags by object id diff --git a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php index c90e4fd2d8..8dee85ccd4 100644 --- a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php @@ -22,15 +22,11 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\Forbidden; -use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\ICollection; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagObjectMapper; -use OCP\SystemTag\ISystemTag; -use OCP\SystemTag\TagNotFoundException; -use OC\SystemTag\SystemTag; /** * Collection containing object ids by object type diff --git a/apps/dav/lib/systemtag/systemtagsrelationscollection.php b/apps/dav/lib/systemtag/systemtagsrelationscollection.php index 4bcb6882a4..44069bca02 100644 --- a/apps/dav/lib/systemtag/systemtagsrelationscollection.php +++ b/apps/dav/lib/systemtag/systemtagsrelationscollection.php @@ -21,6 +21,9 @@ namespace OCA\DAV\SystemTag; +use OCP\SystemTag\ISystemTagManager; +use OCP\SystemTag\ISystemTagObjectMapper; +use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\SimpleCollection; class SystemTagsRelationsCollection extends SimpleCollection { From fe95fd5bec5e4b52112ab68cff0d942bb8ffb226 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 3 Dec 2015 11:26:16 +0100 Subject: [PATCH 3/4] Unit test for system tags plugin --- .../lib/systemtag/systemtagmappingnode.php | 18 + apps/dav/lib/systemtag/systemtagnode.php | 18 +- apps/dav/lib/systemtag/systemtagplugin.php | 10 +- .../systemtagsobjectmappingcollection.php | 9 +- .../unit/systemtag/systemtagmappingnode.php | 84 +++++ .../tests/unit/systemtag/systemtagnode.php | 103 ++++++ .../tests/unit/systemtag/systemtagplugin.php | 308 ++++++++++++++++++ .../systemtag/systemtagsbyidcollection.php | 147 +++++++++ .../systemtagsobjectmappingcollection.php | 215 ++++++++++++ .../systemtagsobjecttypecollection.php | 90 +++++ 10 files changed, 988 insertions(+), 14 deletions(-) create mode 100644 apps/dav/tests/unit/systemtag/systemtagmappingnode.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagnode.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagplugin.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php create mode 100644 apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php diff --git a/apps/dav/lib/systemtag/systemtagmappingnode.php b/apps/dav/lib/systemtag/systemtagmappingnode.php index 03088d734d..cbf8542a4f 100644 --- a/apps/dav/lib/systemtag/systemtagmappingnode.php +++ b/apps/dav/lib/systemtag/systemtagmappingnode.php @@ -70,6 +70,24 @@ class SystemTagMappingNode extends SystemTagNode { parent::__construct($tag, $tagManager); } + /** + * Returns the object id of the relationship + * + * @return string object id + */ + public function getObjectId() { + return $this->objectId; + } + + /** + * Returns the object type of the relationship + * + * @return string object type + */ + public function getObjectType() { + return $this->objectType; + } + /** * Delete tag to object association */ diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php index b09a773793..f7228108b3 100644 --- a/apps/dav/lib/systemtag/systemtagnode.php +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -21,7 +21,6 @@ namespace OCA\DAV\SystemTag; -use OCP\SystemTag\TagAlreadyExistsException; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\Exception\Conflict; @@ -29,6 +28,7 @@ use Sabre\DAV\Exception\Conflict; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; class SystemTagNode implements \Sabre\DAV\INode { @@ -76,23 +76,31 @@ class SystemTagNode implements \Sabre\DAV\INode { * * @param string $name The new name * - * @throws \Sabre\DAV\Exception\MethodNotAllowed + * @throws MethodNotAllowed not allowed to rename node */ public function setName($name) { throw new MethodNotAllowed(); } /** + * Update tag + * * @param string $name new tag name * @param bool $userVisible user visible * @param bool $userAssignable user assignable - * @throws Conflict + * @throws NotFound whenever the given tag id does not exist + * @throws Conflict whenever a tag already exists with the given attributes */ public function update($name, $userVisible, $userAssignable) { try { - $this->tagManager->updateTag($name, $userVisible, $userAssignable); + $this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable); + } catch (TagNotFoundException $e) { + throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); } catch (TagAlreadyExistsException $e) { - throw new Conflict('Tag with the properties "' . $name . '", ' . $userVisible, ', ' . $userAssignable . ' already exists'); + throw new Conflict( + 'Tag with the properties "' . $name . '", ' . + $userVisible . ', ' . $userAssignable . ' already exists' + ); } } diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php index d5591c2849..692b7e9701 100644 --- a/apps/dav/lib/systemtag/systemtagplugin.php +++ b/apps/dav/lib/systemtag/systemtagplugin.php @@ -88,18 +88,18 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { /** * We intercept this to handle POST requests on calendars. * - * @param RequestInterface $request - * @param ResponseInterface $response + * @param RequestInterface $request request object + * @param ResponseInterface $response response object * @return null|false */ - function httpPost(RequestInterface $request, ResponseInterface $response) { + public function httpPost(RequestInterface $request, ResponseInterface $response) { $path = $request->getPath(); // Making sure the node exists try { $node = $this->server->tree->getNodeForPath($path); } catch (NotFound $e) { - return; + return null; } if ($node instanceof SystemTagsByIdCollection || $node instanceof SystemTagsObjectMappingCollection) { @@ -159,7 +159,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { } if (isset($data['userAssignable'])) { - $userVisible = (bool)$data['userAssignable']; + $userAssignable = (bool)$data['userAssignable']; } try { return $this->tagManager->createTag($tagName, $userVisible, $userAssignable); diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php index 6ed959fd88..e81994e0bd 100644 --- a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -24,6 +24,7 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\BadRequest; +use Sabre\DAV\Exception\PreconditionFailed; use Sabre\DAV\ICollection; use OCP\SystemTag\ISystemTagManager; @@ -75,7 +76,7 @@ class SystemTagsObjectMappingCollection implements ICollection { try { $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId); } catch (TagNotFoundException $e) { - throw new Forbidden('Tag with id ' . $tagId . ' does not exist, cannot assign'); + throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign'); } } @@ -103,9 +104,9 @@ class SystemTagsObjectMappingCollection implements ICollection { return []; } $tags = $this->tagManager->getTagsById($tagIds); - return array_map(function($tag) { + return array_values(array_map(function($tag) { return $this->makeNode($tag); - }, $tags); + }, $tags)); } function childExists($tagId) { @@ -114,7 +115,7 @@ class SystemTagsObjectMappingCollection implements ICollection { } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); } catch (TagNotFoundException $e) { - throw new NotFound('Tag with id ' . $tagId . ' not found', 0, $e); + return false; } } diff --git a/apps/dav/tests/unit/systemtag/systemtagmappingnode.php b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php new file mode 100644 index 0000000000..849f7c2fa5 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php @@ -0,0 +1,84 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\Conflict; + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagMappingNode extends SystemTagNode { + + /** + * @var \OCA\DAV\SystemTag\SystemTagMappingNode + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTagObjectMapper + */ + private $tagMapper; + + /** + * @var \OCP\SystemTag\ISystemTag + */ + private $tag; + + protected function setUp() { + parent::setUp(); + + $this->tag = new SystemTag(1, 'Test', true, false); + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagMappingNode( + $this->tag, + 123, + 'files', + $this->tagManager, + $this->tagMapper + ); + } + + public function testGetters() { + parent::testGetters(); + $this->assertEquals(123, $this->node->getObjectId()); + $this->assertEquals('files', $this->node->getObjectType()); + } + + public function testDeleteTag() { + $this->tagManager->expects($this->never()) + ->method('deleteTags'); + $this->tagMapper->expects($this->once()) + ->method('unassignTags') + ->with(123, 'files', 1); + + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testDeleteTagNotFound() { + $this->tagMapper->expects($this->once()) + ->method('unassignTags') + ->with(123, 'files', 1) + ->will($this->throwException(new TagNotFoundException())); + + $this->node->delete(); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagnode.php b/apps/dav/tests/unit/systemtag/systemtagnode.php new file mode 100644 index 0000000000..a43dda3025 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagnode.php @@ -0,0 +1,103 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\Conflict; + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagNode extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagNode + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTag + */ + private $tag; + + protected function setUp() { + parent::setUp(); + + $this->tag = new SystemTag(1, 'Test', true, false); + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagNode($this->tag, $this->tagManager); + } + + public function testGetters() { + $this->assertEquals('1', $this->node->getName()); + $this->assertEquals($this->tag, $this->node->getSystemTag()); + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + public function testSetName() { + $this->node->setName('2'); + } + + public function testUpdateTag() { + $this->tagManager->expects($this->once()) + ->method('updateTag') + ->with(1, 'Renamed', false, true); + $this->node->update('Renamed', false, true); + } + + /** + * @expectedException Sabre\DAV\Exception\Conflict + */ + public function testUpdateTagAlreadyExists() { + $this->tagManager->expects($this->once()) + ->method('updateTag') + ->with(1, 'Renamed', false, true) + ->will($this->throwException(new TagAlreadyExistsException())); + $this->node->update('Renamed', false, true); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testUpdateTagNotFound() { + $this->tagManager->expects($this->once()) + ->method('updateTag') + ->with(1, 'Renamed', false, true) + ->will($this->throwException(new TagNotFoundException())); + $this->node->update('Renamed', false, true); + } + + public function testDeleteTag() { + $this->tagManager->expects($this->once()) + ->method('deleteTags') + ->with('1'); + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testDeleteTagNotFound() { + $this->tagManager->expects($this->once()) + ->method('deleteTags') + ->with('1') + ->will($this->throwException(new TagNotFoundException())); + $this->node->delete(); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagplugin.php b/apps/dav/tests/unit/systemtag/systemtagplugin.php new file mode 100644 index 0000000000..48c9aa69f7 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagplugin.php @@ -0,0 +1,308 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagPlugin extends \Test\TestCase { + + const ID_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::ID_PROPERTYNAME; + const DISPLAYNAME_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::DISPLAYNAME_PROPERTYNAME; + const USERVISIBLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USERVISIBLE_PROPERTYNAME; + const USERASSIGNABLE_PROPERTYNAME = \OCA\DAV\SystemTag\SystemTagPlugin::USERASSIGNABLE_PROPERTYNAME; + + /** + * @var \Sabre\DAV\Server + */ + private $server; + + /** + * @var \Sabre\DAV\Tree + */ + private $tree; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCA\DAV\Connector\Sabre\TagsPlugin + */ + private $plugin; + + public function setUp() { + parent::setUp(); + $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree') + ->disableOriginalConstructor() + ->getMock(); + + $this->server = new \Sabre\DAV\Server($this->tree); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + + $this->plugin = new \OCA\DAV\SystemTag\SystemTagPlugin($this->tagManager); + $this->plugin->initialize($this->server); + } + + public function testGetProperties() { + $systemTag = new SystemTag(1, 'Test', true, true); + $requestedProperties = [ + self::ID_PROPERTYNAME, + self::DISPLAYNAME_PROPERTYNAME, + self::USERVISIBLE_PROPERTYNAME, + self::USERASSIGNABLE_PROPERTYNAME + ]; + $expectedProperties = [ + 200 => [ + self::ID_PROPERTYNAME => '1', + self::DISPLAYNAME_PROPERTYNAME => 'Test', + self::USERVISIBLE_PROPERTYNAME => 1, + self::USERASSIGNABLE_PROPERTYNAME => 1, + ] + ]; + + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode') + ->disableOriginalConstructor() + ->getMock(); + $node->expects($this->any()) + ->method('getSystemTag') + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtag/1') + ->will($this->returnValue($node)); + + $propFind = new \Sabre\DAV\PropFind( + '/systemtag/1', + $requestedProperties, + 0 + ); + + $this->plugin->handleGetProperties( + $propFind, + $node + ); + + $result = $propFind->getResultForMultiStatus(); + + $this->assertEmpty($result[404]); + unset($result[404]); + $this->assertEquals($expectedProperties, $result); + } + + public function testUpdateProperties() { + $systemTag = new SystemTag(1, 'Test', true, false); + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagNode') + ->disableOriginalConstructor() + ->getMock(); + $node->expects($this->any()) + ->method('getSystemTag') + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtag/1') + ->will($this->returnValue($node)); + + $node->expects($this->once()) + ->method('update') + ->with('Test changed', false, true); + + // properties to set + $propPatch = new \Sabre\DAV\PropPatch(array( + self::DISPLAYNAME_PROPERTYNAME => 'Test changed', + self::USERVISIBLE_PROPERTYNAME => 0, + self::USERASSIGNABLE_PROPERTYNAME => 1, + )); + + $this->plugin->handleUpdateProperties( + '/systemtag/1', + $propPatch + ); + + $propPatch->commit(); + + // all requested properties removed, as they were processed already + $this->assertEmpty($propPatch->getRemainingMutations()); + + $result = $propPatch->getResult(); + $this->assertEquals(200, $result[self::DISPLAYNAME_PROPERTYNAME]); + $this->assertEquals(200, $result[self::USERASSIGNABLE_PROPERTYNAME]); + $this->assertEquals(200, $result[self::USERVISIBLE_PROPERTYNAME]); + } + + public function testCreateTagInByIdCollection() { + $systemTag = new SystemTag(1, 'Test', true, false); + + $requestData = json_encode([ + 'name' => 'Test', + 'userVisible' => true, + 'userAssignable' => false, + ]); + + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsByIdCollection') + ->disableOriginalConstructor() + ->getMock(); + $this->tagManager->expects($this->once()) + ->method('createTag') + ->with('Test', true, false) + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtags') + ->will($this->returnValue($node)); + + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/systemtags')); + + $request->expects($this->once()) + ->method('getBodyAsString') + ->will($this->returnValue($requestData)); + + $request->expects($this->once()) + ->method('getHeader') + ->with('Content-Type') + ->will($this->returnValue('application/json')); + + $request->expects($this->once()) + ->method('getUrl') + ->will($this->returnValue('http://example.com/dav/systemtags')); + + $response->expects($this->once()) + ->method('setHeader') + ->with('Location', 'http://example.com/dav/systemtags/1'); + + $this->plugin->httpPost($request, $response); + } + + public function nodeClassProvider() { + return [ + ['\OCA\DAV\SystemTag\SystemTagsByIdCollection'], + ['\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection'], + ]; + } + + public function testCreateTagInMappingCollection() { + $systemTag = new SystemTag(1, 'Test', true, false); + + $requestData = json_encode([ + 'name' => 'Test', + 'userVisible' => true, + 'userAssignable' => false, + ]); + + $node = $this->getMockBuilder('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection') + ->disableOriginalConstructor() + ->getMock(); + + $this->tagManager->expects($this->once()) + ->method('createTag') + ->with('Test', true, false) + ->will($this->returnValue($systemTag)); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtags-relations/files/12') + ->will($this->returnValue($node)); + + $node->expects($this->once()) + ->method('createFile') + ->with(1); + + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/systemtags-relations/files/12')); + + $request->expects($this->once()) + ->method('getBodyAsString') + ->will($this->returnValue($requestData)); + + $request->expects($this->once()) + ->method('getHeader') + ->with('Content-Type') + ->will($this->returnValue('application/json')); + + $request->expects($this->once()) + ->method('getBaseUrl') + ->will($this->returnValue('http://example.com/dav/')); + + $response->expects($this->once()) + ->method('setHeader') + ->with('Location', 'http://example.com/dav/systemtags/1'); + + $this->plugin->httpPost($request, $response); + } + + /** + * @dataProvider nodeClassProvider + * @expectedException Sabre\DAV\Exception\Conflict + */ + public function testCreateTagConflict($nodeClass) { + $requestData = json_encode([ + 'name' => 'Test', + 'userVisible' => true, + 'userAssignable' => false, + ]); + + $node = $this->getMockBuilder($nodeClass) + ->disableOriginalConstructor() + ->getMock(); + $this->tagManager->expects($this->once()) + ->method('createTag') + ->with('Test', true, false) + ->will($this->throwException(new TagAlreadyExistsException('Tag already exists'))); + + $this->tree->expects($this->any()) + ->method('getNodeForPath') + ->with('/systemtags') + ->will($this->returnValue($node)); + + $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface') + ->disableOriginalConstructor() + ->getMock(); + $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface') + ->disableOriginalConstructor() + ->getMock(); + + $request->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/systemtags')); + + $request->expects($this->once()) + ->method('getBodyAsString') + ->will($this->returnValue($requestData)); + + $request->expects($this->once()) + ->method('getHeader') + ->with('Content-Type') + ->will($this->returnValue('application/json')); + + $this->plugin->httpPost($request, $response); + } + +} diff --git a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php new file mode 100644 index 0000000000..fdaaf2cd00 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php @@ -0,0 +1,147 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagsByIdCollection extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagsByIdCollection + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + protected function setUp() { + parent::setUp(); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagsByIdCollection($this->tagManager); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateFile() { + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateDirectory() { + $this->node->createDirectory('789'); + } + + public function testGetChild() { + $tag = new SystemTag(123, 'Test', true, false); + + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('123') + ->will($this->returnValue([$tag])); + + $childNode = $this->node->getChild('123'); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); + $this->assertEquals('123', $childNode->getName()); + $this->assertEquals($tag, $childNode->getSystemTag()); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testGetChildInvalidName() { + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('invalid') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->getChild('invalid'); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildNotFound() { + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('444') + ->will($this->throwException(new TagNotFoundException())); + + $this->node->getChild('444'); + } + + public function testGetChildren() { + $tag1 = new SystemTag(123, 'One', true, false); + $tag2 = new SystemTag(456, 'Two', true, true); + + $this->tagManager->expects($this->once()) + ->method('getAllTags') + ->with(true) + ->will($this->returnValue([$tag1, $tag2])); + + $children = $this->node->getChildren(); + + $this->assertCount(2, $children); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[0]); + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $children[1]); + $this->assertEquals($tag1, $children[0]->getSystemTag()); + $this->assertEquals($tag2, $children[1]->getSystemTag()); + } + + public function testGetChildrenEmpty() { + $this->tagManager->expects($this->once()) + ->method('getAllTags') + ->with(true) + ->will($this->returnValue([])); + $this->assertCount(0, $this->node->getChildren()); + } + + public function testChildExists() { + $tag = new SystemTag(123, 'One', true, false); + + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('123') + ->will($this->returnValue([$tag])); + + $this->assertTrue($this->node->childExists('123')); + } + + public function testChildExistsNotFound() { + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('123') + ->will($this->throwException(new TagNotFoundException())); + + $this->assertFalse($this->node->childExists('123')); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testChildExistsBadRequest() { + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('invalid') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->childExists('invalid'); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php new file mode 100644 index 0000000000..1a9ffa6f4a --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php @@ -0,0 +1,215 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + + +use OC\SystemTag\SystemTag; +use OCP\SystemTag\TagNotFoundException; +use OCP\SystemTag\TagAlreadyExistsException; + +class SystemTagsObjectMappingCollection extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTagMapper + */ + private $tagMapper; + + protected function setUp() { + parent::setUp(); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagsObjectMappingCollection ( + 111, + 'files', + $this->tagManager, + $this->tagMapper + ); + } + + public function testAssignTag() { + $this->tagMapper->expects($this->once()) + ->method('assignTags') + ->with(111, 'files', '555'); + + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + public function testAssignTagNotFound() { + $this->tagMapper->expects($this->once()) + ->method('assignTags') + ->with(111, 'files', '555') + ->will($this->throwException(new TagNotFoundException())); + + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateDirectory() { + $this->node->createDirectory('789'); + } + + public function testGetChild() { + $tag = new SystemTag(555, 'TheTag', true, false); + + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555', true) + ->will($this->returnValue(true)); + + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with('555') + ->will($this->returnValue([$tag])); + + $childNode = $this->node->getChild('555'); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); + $this->assertEquals('555', $childNode->getName()); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildRelationNotFound() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '777') + ->will($this->returnValue(false)); + + $this->node->getChild('777'); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testGetChildInvalidId() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', 'badid') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->getChild('badid'); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildTagDoesNotExist() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '777') + ->will($this->throwException(new TagNotFoundException())); + + $this->node->getChild('777'); + } + + public function testGetChildren() { + $tag1 = new SystemTag(555, 'TagOne', true, false); + $tag2 = new SystemTag(556, 'TagTwo', true, true); + + $this->tagMapper->expects($this->once()) + ->method('getTagIdsForObjects') + ->with(111, 'files') + ->will($this->returnValue(['111' => ['555', '556']])); + + $this->tagManager->expects($this->once()) + ->method('getTagsById') + ->with(['555', '556']) + ->will($this->returnValue(['555' => $tag1, '666' => $tag2])); + + $children = $this->node->getChildren(); + + $this->assertCount(2, $children); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[0]); + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[1]); + + $this->assertEquals(111, $children[0]->getObjectId()); + $this->assertEquals('files', $children[0]->getObjectType()); + $this->assertEquals($tag1, $children[0]->getSystemTag()); + + $this->assertEquals(111, $children[1]->getObjectId()); + $this->assertEquals('files', $children[1]->getObjectType()); + $this->assertEquals($tag2, $children[1]->getSystemTag()); + } + + public function testChildExists() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555') + ->will($this->returnValue(true)); + + $this->assertTrue($this->node->childExists('555')); + } + + public function testChildExistsNotFound() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555') + ->will($this->returnValue(false)); + + $this->assertFalse($this->node->childExists('555')); + } + + public function testChildExistsTagNotFound() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555') + ->will($this->throwException(new TagNotFoundException())); + + $this->assertFalse($this->node->childExists('555')); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testChildExistsInvalidId() { + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with(111, 'files', '555') + ->will($this->throwException(new \InvalidArgumentException())); + + $this->node->childExists('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testDelete() { + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testSetName() { + $this->node->setName('somethingelse'); + } + + public function testGetName() { + $this->assertEquals('111', $this->node->getName()); + } +} diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php new file mode 100644 index 0000000000..39223ff912 --- /dev/null +++ b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php @@ -0,0 +1,90 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCA\DAV\Tests\Unit\SystemTag; + +class SystemTagsObjectTypeCollection extends \Test\TestCase { + + /** + * @var \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection + */ + private $node; + + /** + * @var \OCP\SystemTag\ISystemTagManager + */ + private $tagManager; + + /** + * @var \OCP\SystemTag\ISystemTagMapper + */ + private $tagMapper; + + protected function setUp() { + parent::setUp(); + + $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + + $this->node = new \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection( + 'files', + $this->tagManager, + $this->tagMapper + ); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateFile() { + $this->node->createFile('555'); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testForbiddenCreateDirectory() { + $this->node->createDirectory('789'); + } + + public function testGetChild() { + $childNode = $this->node->getChild('files'); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagsObjectMappingCollection', $childNode); + $this->assertEquals('files', $childNode->getName()); + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + public function testGetChildren() { + $this->node->getChildren(); + } + + public function testChildExists() { + $this->assertTrue($this->node->childExists('123')); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testDelete() { + $this->node->delete(); + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testSetName() { + $this->node->setName('somethingelse'); + } + + public function testGetName() { + $this->assertEquals('files', $this->node->getName()); + } +} From 316b907a13fcca9781f09b0f1a2a2d7324e42770 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 4 Dec 2015 17:30:22 +0100 Subject: [PATCH 4/4] Fixed system tags DAV and API and docs --- apps/dav/lib/systemtag/systemtagnode.php | 3 +++ apps/dav/lib/systemtag/systemtagplugin.php | 16 ++++++++---- .../systemtag/systemtagsbyidcollection.php | 5 ++-- .../systemtagsobjectmappingcollection.php | 13 +++++----- .../systemtagsobjecttypecollection.php | 2 +- .../systemtag/systemtagsbyidcollection.php | 24 ++++++++--------- .../systemtagsobjectmappingcollection.php | 26 +++++++++---------- lib/private/systemtag/systemtagmanager.php | 4 +-- .../systemtag/systemtagobjectmapper.php | 2 +- lib/public/systemtag/isystemtagmanager.php | 2 +- tests/lib/systemtag/systemtagmanagertest.php | 6 ++--- .../systemtag/systemtagobjectmappertest.php | 2 +- 12 files changed, 57 insertions(+), 48 deletions(-) diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php index f7228108b3..7ab4a8a14f 100644 --- a/apps/dav/lib/systemtag/systemtagnode.php +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -30,6 +30,9 @@ use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\TagNotFoundException; use OCP\SystemTag\TagAlreadyExistsException; +/** + * DAV node representing a system tag, with the name being the tag id. + */ class SystemTagNode implements \Sabre\DAV\INode { /** diff --git a/apps/dav/lib/systemtag/systemtagplugin.php b/apps/dav/lib/systemtag/systemtagplugin.php index 692b7e9701..51db063254 100644 --- a/apps/dav/lib/systemtag/systemtagplugin.php +++ b/apps/dav/lib/systemtag/systemtagplugin.php @@ -33,6 +33,13 @@ use OCP\SystemTag\TagAlreadyExistsException; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; +/** + * Sabre plugin to handle system tags: + * + * - makes it possible to create new tags with POST operation + * - get/set Webdav properties for tags + * + */ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { // namespace @@ -86,7 +93,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { } /** - * We intercept this to handle POST requests on calendars. + * POST operation on system tag collections * * @param RequestInterface $request request object * @param ResponseInterface $response response object @@ -130,18 +137,17 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { /** * Creates a new tag * - * @param string $data + * @param string $data JSON encoded string containing the properties of the tag to create * @param string $contentType content type of the data * @return ISystemTag newly created system tag * * @throws BadRequest if a field was missing - * @throws Conflict + * @throws Conflict if a tag with the same properties already exists * @throws UnsupportedMediaType if the content type is not supported */ private function createTag($data, $contentType = 'application/json') { if ($contentType === 'application/json') { $data = json_decode($data, true); - // TODO: application/x-www-form-urlencoded ? } else { throw new UnsupportedMediaType(); } @@ -164,7 +170,7 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin { try { return $this->tagManager->createTag($tagName, $userVisible, $userAssignable); } catch (TagAlreadyExistsException $e) { - throw new Conflict('Tag already exists'); + throw new Conflict('Tag already exists', 0, $e); } } diff --git a/apps/dav/lib/systemtag/systemtagsbyidcollection.php b/apps/dav/lib/systemtag/systemtagsbyidcollection.php index 0164b9b0b3..e7b7b6d0ac 100644 --- a/apps/dav/lib/systemtag/systemtagsbyidcollection.php +++ b/apps/dav/lib/systemtag/systemtagsbyidcollection.php @@ -56,7 +56,7 @@ class SystemTagsByIdCollection implements ICollection { function getChild($name) { try { - $tags = $this->tagManager->getTagsById($name); + $tags = $this->tagManager->getTagsByIds([$name]); return $this->makeNode(current($tags)); } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); @@ -66,7 +66,6 @@ class SystemTagsByIdCollection implements ICollection { } function getChildren() { - // TODO: set visibility filter based on principal/permissions ? $tags = $this->tagManager->getAllTags(true); return array_map(function($tag) { return $this->makeNode($tag); @@ -75,7 +74,7 @@ class SystemTagsByIdCollection implements ICollection { function childExists($name) { try { - $this->tagManager->getTagsById($name); + $this->tagManager->getTagsByIds([$name]); return true; } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php index e81994e0bd..89e8620614 100644 --- a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -86,8 +86,8 @@ class SystemTagsObjectMappingCollection implements ICollection { function getChild($tagId) { try { - if ($this->tagMapper->haveTag($this->objectId, $this->objectType, $tagId, true)) { - $tag = $this->tagManager->getTagsById($tagId); + if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) { + $tag = $this->tagManager->getTagsByIds([$tagId]); return $this->makeNode(current($tag)); } throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId); @@ -99,11 +99,11 @@ class SystemTagsObjectMappingCollection implements ICollection { } function getChildren() { - $tagIds = current($this->tagMapper->getTagIdsForObjects($this->objectId, $this->objectType)); + $tagIds = current($this->tagMapper->getTagIdsForObjects([$this->objectId], $this->objectType)); if (empty($tagIds)) { return []; } - $tags = $this->tagManager->getTagsById($tagIds); + $tags = $this->tagManager->getTagsByIds($tagIds); return array_values(array_map(function($tag) { return $this->makeNode($tag); }, $tags)); @@ -111,7 +111,7 @@ class SystemTagsObjectMappingCollection implements ICollection { function childExists($tagId) { try { - return ($this->tagMapper->haveTag($this->objectId, $this->objectType, $tagId, true)); + return ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)); } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); } catch (TagNotFoundException $e) { @@ -141,7 +141,8 @@ class SystemTagsObjectMappingCollection implements ICollection { } /** - * Create a sabre node for the given system tag + * Create a sabre node for the mapping of the + * given system tag to the collection's object * * @param ISystemTag $tag * diff --git a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php index 8dee85ccd4..e544073613 100644 --- a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php @@ -62,7 +62,7 @@ class SystemTagsObjectTypeCollection implements ICollection { } function createFile($name, $data = null) { - throw new Forbidden('Permission denied to create collections'); + throw new Forbidden('Permission denied to create nodes'); } function createDirectory($name) { diff --git a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php index fdaaf2cd00..104ce36603 100644 --- a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php +++ b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php @@ -51,8 +51,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { $tag = new SystemTag(123, 'Test', true, false); $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('123') + ->method('getTagsByIds') + ->with(['123']) ->will($this->returnValue([$tag])); $childNode = $this->node->getChild('123'); @@ -67,8 +67,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { */ public function testGetChildInvalidName() { $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('invalid') + ->method('getTagsByIds') + ->with(['invalid']) ->will($this->throwException(new \InvalidArgumentException())); $this->node->getChild('invalid'); @@ -79,8 +79,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { */ public function testGetChildNotFound() { $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('444') + ->method('getTagsByIds') + ->with(['444']) ->will($this->throwException(new TagNotFoundException())); $this->node->getChild('444'); @@ -117,8 +117,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { $tag = new SystemTag(123, 'One', true, false); $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('123') + ->method('getTagsByIds') + ->with(['123']) ->will($this->returnValue([$tag])); $this->assertTrue($this->node->childExists('123')); @@ -126,8 +126,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { public function testChildExistsNotFound() { $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('123') + ->method('getTagsByIds') + ->with(['123']) ->will($this->throwException(new TagNotFoundException())); $this->assertFalse($this->node->childExists('123')); @@ -138,8 +138,8 @@ class SystemTagsByIdCollection extends \Test\TestCase { */ public function testChildExistsBadRequest() { $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('invalid') + ->method('getTagsByIds') + ->with(['invalid']) ->will($this->throwException(new \InvalidArgumentException())); $this->node->childExists('invalid'); diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php index 1a9ffa6f4a..6e15bb78e7 100644 --- a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php @@ -76,13 +76,13 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555', true) + ->with([111], 'files', '555', true) ->will($this->returnValue(true)); $this->tagManager->expects($this->once()) - ->method('getTagsById') - ->with('555') - ->will($this->returnValue([$tag])); + ->method('getTagsByIds') + ->with(['555']) + ->will($this->returnValue(['555' => $tag])); $childNode = $this->node->getChild('555'); @@ -96,7 +96,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testGetChildRelationNotFound() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '777') + ->with([111], 'files', '777') ->will($this->returnValue(false)); $this->node->getChild('777'); @@ -108,7 +108,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testGetChildInvalidId() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', 'badid') + ->with([111], 'files', 'badid') ->will($this->throwException(new \InvalidArgumentException())); $this->node->getChild('badid'); @@ -120,7 +120,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testGetChildTagDoesNotExist() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '777') + ->with([111], 'files', '777') ->will($this->throwException(new TagNotFoundException())); $this->node->getChild('777'); @@ -132,11 +132,11 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->tagMapper->expects($this->once()) ->method('getTagIdsForObjects') - ->with(111, 'files') + ->with([111], 'files') ->will($this->returnValue(['111' => ['555', '556']])); $this->tagManager->expects($this->once()) - ->method('getTagsById') + ->method('getTagsByIds') ->with(['555', '556']) ->will($this->returnValue(['555' => $tag1, '666' => $tag2])); @@ -159,7 +159,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testChildExists() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555') + ->with([111], 'files', '555') ->will($this->returnValue(true)); $this->assertTrue($this->node->childExists('555')); @@ -168,7 +168,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testChildExistsNotFound() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555') + ->with([111], 'files', '555') ->will($this->returnValue(false)); $this->assertFalse($this->node->childExists('555')); @@ -177,7 +177,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testChildExistsTagNotFound() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555') + ->with([111], 'files', '555') ->will($this->throwException(new TagNotFoundException())); $this->assertFalse($this->node->childExists('555')); @@ -189,7 +189,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { public function testChildExistsInvalidId() { $this->tagMapper->expects($this->once()) ->method('haveTag') - ->with(111, 'files', '555') + ->with([111], 'files', '555') ->will($this->throwException(new \InvalidArgumentException())); $this->node->childExists('555'); diff --git a/lib/private/systemtag/systemtagmanager.php b/lib/private/systemtag/systemtagmanager.php index 8caf10d69d..7f239dc84c 100644 --- a/lib/private/systemtag/systemtagmanager.php +++ b/lib/private/systemtag/systemtagmanager.php @@ -63,7 +63,7 @@ class SystemTagManager implements ISystemTagManager { /** * {@inheritdoc} */ - public function getTagsById($tagIds) { + public function getTagsByIds($tagIds) { if (!is_array($tagIds)) { $tagIds = [$tagIds]; } @@ -242,7 +242,7 @@ class SystemTagManager implements ISystemTagManager { $tagNotFoundException = null; try { - $this->getTagsById($tagIds); + $this->getTagsByIds($tagIds); } catch (TagNotFoundException $e) { $tagNotFoundException = $e; } diff --git a/lib/private/systemtag/systemtagobjectmapper.php b/lib/private/systemtag/systemtagobjectmapper.php index bb64a35456..988fa66d77 100644 --- a/lib/private/systemtag/systemtagobjectmapper.php +++ b/lib/private/systemtag/systemtagobjectmapper.php @@ -213,7 +213,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { * @throws \OCP\SystemTag\TagNotFoundException if at least one tag did not exist */ private function assertTagsExist($tagIds) { - $tags = $this->tagManager->getTagsById($tagIds); + $tags = $this->tagManager->getTagsByIds($tagIds); if (count($tags) !== count($tagIds)) { // at least one tag missing, bail out $foundTagIds = array_map( diff --git a/lib/public/systemtag/isystemtagmanager.php b/lib/public/systemtag/isystemtagmanager.php index 4e3b263e56..6e8fed36dc 100644 --- a/lib/public/systemtag/isystemtagmanager.php +++ b/lib/public/systemtag/isystemtagmanager.php @@ -41,7 +41,7 @@ interface ISystemTagManager { * * @since 9.0.0 */ - public function getTagsById($tagIds); + public function getTagsByIds($tagIds); /** * Returns the tag object matching the given attributes. diff --git a/tests/lib/systemtag/systemtagmanagertest.php b/tests/lib/systemtag/systemtagmanagertest.php index 8498b85519..97c072f33f 100644 --- a/tests/lib/systemtag/systemtagmanagertest.php +++ b/tests/lib/systemtag/systemtagmanagertest.php @@ -250,7 +250,7 @@ class SystemTagManagerTest extends TestCase { $tag1 = $this->tagManager->createTag('one', true, false); $tag2 = $this->tagManager->createTag('two', false, true); - $tagList = $this->tagManager->getTagsById([$tag1->getId(), $tag2->getId()]); + $tagList = $this->tagManager->getTagsByIds([$tag1->getId(), $tag2->getId()]); $this->assertCount(2, $tagList); @@ -270,7 +270,7 @@ class SystemTagManagerTest extends TestCase { */ public function testGetNonExistingTagsById() { $tag1 = $this->tagManager->createTag('one', true, false); - $this->tagManager->getTagsById([$tag1->getId(), 100, 101]); + $this->tagManager->getTagsByIds([$tag1->getId(), 100, 101]); } /** @@ -278,7 +278,7 @@ class SystemTagManagerTest extends TestCase { */ public function testGetInvalidTagIdFormat() { $tag1 = $this->tagManager->createTag('one', true, false); - $this->tagManager->getTagsById([$tag1->getId() . 'suffix']); + $this->tagManager->getTagsByIds([$tag1->getId() . 'suffix']); } public function updateTagProvider() { diff --git a/tests/lib/systemtag/systemtagobjectmappertest.php b/tests/lib/systemtag/systemtagobjectmappertest.php index 43d0b8c696..4ea80c216e 100644 --- a/tests/lib/systemtag/systemtagobjectmappertest.php +++ b/tests/lib/systemtag/systemtagobjectmappertest.php @@ -74,7 +74,7 @@ class SystemTagObjectMapperTest extends TestCase { $this->tag3 = new SystemTag(3, 'testtag3', false, false); $this->tagManager->expects($this->any()) - ->method('getTagsById') + ->method('getTagsByIds') ->will($this->returnCallback(function($tagIds) { $result = []; if (in_array(1, $tagIds)) {