diff options
author | Vincent Petry <pvince81@owncloud.com> | 2016-01-20 11:47:23 +0100 |
---|---|---|
committer | Vincent Petry <pvince81@owncloud.com> | 2016-01-21 14:09:27 +0100 |
commit | 5639e41cb066eba2636dadd283365d6f5e9e70b3 (patch) | |
tree | 3e4f4b66b5c5385a60b3d4c1dbe31068db44dbc1 /apps | |
parent | 2540ac431c2d01de8f4faa5721ecf00247c4a1f8 (diff) | |
download | nextcloud-server-5639e41cb066eba2636dadd283365d6f5e9e70b3.tar.gz nextcloud-server-5639e41cb066eba2636dadd283365d6f5e9e70b3.zip |
Fix DAV to respect system tags permissions
When queried as regular user, visible tags are not displayed in result
sets and queries for existence will return false.
Non-assignable or non-visible tags cannot be
renamed/assigned/unassigned.
User is not allowed to change tag permissions, only to change the name
if the tag is also assignable.
Diffstat (limited to 'apps')
12 files changed, 620 insertions, 109 deletions
diff --git a/apps/dav/lib/rootcollection.php b/apps/dav/lib/rootcollection.php index 0afde97a9e7..733341b1eaa 100644 --- a/apps/dav/lib/rootcollection.php +++ b/apps/dav/lib/rootcollection.php @@ -58,10 +58,13 @@ class RootCollection extends SimpleCollection { $caldavBackend = new CalDavBackend($db); $calendarRoot = new CalendarRoot($userPrincipalBackend, $caldavBackend, 'principals/users'); $calendarRoot->disableListing = $disableListing; + $isAdmin = \OC::$server->getGroupManager()->isAdmin(\OC::$server->getUserSession()->getUser()->getUID()); $systemTagCollection = new SystemTag\SystemTagsByIdCollection( + $isAdmin, \OC::$server->getSystemTagManager() ); $systemTagRelationsCollection = new SystemTag\SystemTagsRelationsCollection( + $isAdmin, \OC::$server->getSystemTagManager(), \OC::$server->getSystemTagObjectMapper() ); diff --git a/apps/dav/lib/systemtag/systemtagmappingnode.php b/apps/dav/lib/systemtag/systemtagmappingnode.php index 6911634975b..bb2936c13dc 100644 --- a/apps/dav/lib/systemtag/systemtagmappingnode.php +++ b/apps/dav/lib/systemtag/systemtagmappingnode.php @@ -23,6 +23,7 @@ namespace OCA\DAV\SystemTag; use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\Exception\Forbidden; use OCP\SystemTag\ISystemTag; use OCP\SystemTag\ISystemTagManager; @@ -55,6 +56,7 @@ class SystemTagMappingNode extends SystemTagNode { * @param ISystemTag $tag system tag * @param string $objectId * @param string $objectType + * @param bool $isAdmin whether to allow permissions for admin * @param ISystemTagManager $tagManager * @param ISystemTagObjectMapper $tagMapper */ @@ -62,13 +64,14 @@ class SystemTagMappingNode extends SystemTagNode { ISystemTag $tag, $objectId, $objectType, + $isAdmin, ISystemTagManager $tagManager, ISystemTagObjectMapper $tagMapper ) { $this->objectId = $objectId; $this->objectType = $objectType; $this->tagMapper = $tagMapper; - parent::__construct($tag, $tagManager); + parent::__construct($tag, $isAdmin, $tagManager); } /** @@ -94,6 +97,14 @@ class SystemTagMappingNode extends SystemTagNode { */ public function delete() { try { + if (!$this->isAdmin) { + if (!$this->tag->isUserVisible()) { + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found'); + } + if (!$this->tag->isUserAssignable()) { + throw new Forbidden('No permission to unassign tag ' . $this->tag->getId()); + } + } $this->tagMapper->unassignTags($this->objectId, $this->objectType, $this->tag->getId()); } catch (TagNotFoundException $e) { // can happen if concurrent deletion occurred diff --git a/apps/dav/lib/systemtag/systemtagnode.php b/apps/dav/lib/systemtag/systemtagnode.php index eff1199a43c..ecdb39a762c 100644 --- a/apps/dav/lib/systemtag/systemtagnode.php +++ b/apps/dav/lib/systemtag/systemtagnode.php @@ -22,6 +22,7 @@ namespace OCA\DAV\SystemTag; +use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\Exception\MethodNotAllowed; use Sabre\DAV\Exception\Conflict; @@ -47,13 +48,22 @@ class SystemTagNode implements \Sabre\DAV\INode { protected $tagManager; /** + * Whether to allow permissions for admins + * + * @var bool + */ + protected $isAdmin; + + /** * Sets up the node, expects a full path name * * @param ISystemTag $tag system tag + * @param bool $isAdmin whether to allow operations for admins * @param ISystemTagManager $tagManager */ - public function __construct(ISystemTag $tag, ISystemTagManager $tagManager) { + public function __construct(ISystemTag $tag, $isAdmin, ISystemTagManager $tagManager) { $this->tag = $tag; + $this->isAdmin = $isAdmin; $this->tagManager = $tagManager; } @@ -97,6 +107,21 @@ class SystemTagNode implements \Sabre\DAV\INode { */ public function update($name, $userVisible, $userAssignable) { try { + if (!$this->isAdmin) { + if (!$this->tag->isUserVisible()) { + throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); + } + if (!$this->tag->isUserAssignable()) { + throw new Forbidden('No permission to update tag ' . $this->tag->getId()); + } + + // only renaming is allowed for regular users + if ($userVisible !== $this->tag->isUserVisible() + || $userAssignable !== $this->tag->isUserAssignable() + ) { + throw new Forbidden('No permission to update permissions for tag ' . $this->tag->getId()); + } + } $this->tagManager->updateTag($this->tag->getId(), $name, $userVisible, $userAssignable); } catch (TagNotFoundException $e) { throw new NotFound('Tag with id ' . $this->tag->getId() . ' does not exist'); @@ -118,6 +143,14 @@ class SystemTagNode implements \Sabre\DAV\INode { public function delete() { try { + if (!$this->isAdmin) { + if (!$this->tag->isUserVisible()) { + throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found'); + } + if (!$this->tag->isUserAssignable()) { + throw new Forbidden('No permission to delete tag ' . $this->tag->getId()); + } + } $this->tagManager->deleteTags($this->tag->getId()); } catch (TagNotFoundException $e) { // can happen if concurrent deletion occurred diff --git a/apps/dav/lib/systemtag/systemtagsbyidcollection.php b/apps/dav/lib/systemtag/systemtagsbyidcollection.php index 5df3d3f8310..b5d59b02d00 100644 --- a/apps/dav/lib/systemtag/systemtagsbyidcollection.php +++ b/apps/dav/lib/systemtag/systemtagsbyidcollection.php @@ -40,11 +40,20 @@ class SystemTagsByIdCollection implements ICollection { private $tagManager; /** + * Whether the include tags visible to the admin + * + * @var bool + */ + private $isAdmin; + + /** * SystemTagsByIdCollection constructor. * * @param ISystemTagManager $tagManager + * @param bool $isAdmin whether to include tags visible to the admin */ - public function __construct($tagManager) { + public function __construct($isAdmin, $tagManager) { + $this->isAdmin = $isAdmin; $this->tagManager = $tagManager; } @@ -69,8 +78,12 @@ class SystemTagsByIdCollection implements ICollection { */ function getChild($name) { try { - $tags = $this->tagManager->getTagsByIds([$name]); - return $this->makeNode(current($tags)); + $tag = $this->tagManager->getTagsByIds([$name]); + $tag = current($tag); + if (!$this->isAdmin && !$tag->isUserVisible()) { + throw new NotFound('Tag with id ' . $name . ' not found'); + } + return $this->makeNode($tag); } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); } catch (TagNotFoundException $e) { @@ -79,7 +92,12 @@ class SystemTagsByIdCollection implements ICollection { } function getChildren() { - $tags = $this->tagManager->getAllTags(true); + $visibilityFilter = true; + if ($this->isAdmin) { + $visibilityFilter = null; + } + + $tags = $this->tagManager->getAllTags($visibilityFilter); return array_map(function($tag) { return $this->makeNode($tag); }, $tags); @@ -90,7 +108,11 @@ class SystemTagsByIdCollection implements ICollection { */ function childExists($name) { try { - $this->tagManager->getTagsByIds([$name]); + $tag = $this->tagManager->getTagsByIds([$name]); + $tag = current($tag); + if (!$this->isAdmin && !$tag->isUserVisible()) { + return false; + } return true; } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); @@ -128,6 +150,6 @@ class SystemTagsByIdCollection implements ICollection { * @return SystemTagNode */ private function makeNode(ISystemTag $tag) { - return new SystemTagNode($tag, $this->tagManager); + return new SystemTagNode($tag, $this->isAdmin, $this->tagManager); } } diff --git a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php index 3d683454673..eb75ed06393 100644 --- a/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjectmappingcollection.php @@ -58,22 +58,42 @@ class SystemTagsObjectMappingCollection implements ICollection { private $tagMapper; /** + * Whether to return results only visible for admins + * + * @var bool + */ + private $isAdmin; + + + /** * Constructor * * @param string $objectId object id * @param string $objectType object type + * @param bool $isAdmin whether to return results visible only for admins * @param ISystemTagManager $tagManager * @param ISystemTagObjectMapper $tagMapper */ - public function __construct($objectId, $objectType, $tagManager, $tagMapper) { + public function __construct($objectId, $objectType, $isAdmin, $tagManager, $tagMapper) { $this->tagManager = $tagManager; $this->tagMapper = $tagMapper; $this->objectId = $objectId; $this->objectType = $objectType; + $this->isAdmin = $isAdmin; } function createFile($tagId, $data = null) { try { + if (!$this->isAdmin) { + $tag = $this->tagManager->getTagsByIds($tagId); + $tag = current($tag); + if (!$tag->isUserVisible()) { + throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign'); + } + if (!$tag->isUserAssignable()) { + throw new Forbidden('No permission to assign tag ' . $tag->getId()); + } + } $this->tagMapper->assignTags($this->objectId, $this->objectType, $tagId); } catch (TagNotFoundException $e) { throw new PreconditionFailed('Tag with id ' . $tagId . ' does not exist, cannot assign'); @@ -88,7 +108,10 @@ class SystemTagsObjectMappingCollection implements ICollection { try { if ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)) { $tag = $this->tagManager->getTagsByIds([$tagId]); - return $this->makeNode(current($tag)); + $tag = current($tag); + if ($this->isAdmin || $tag->isUserVisible()) { + return $this->makeNode($tag); + } } throw new NotFound('Tag with id ' . $tagId . ' not present for object ' . $this->objectId); } catch (\InvalidArgumentException $e) { @@ -104,6 +127,12 @@ class SystemTagsObjectMappingCollection implements ICollection { return []; } $tags = $this->tagManager->getTagsByIds($tagIds); + if (!$this->isAdmin) { + // filter out non-visible tags + $tags = array_filter($tags, function($tag) { + return $tag->isUserVisible(); + }); + } return array_values(array_map(function($tag) { return $this->makeNode($tag); }, $tags)); @@ -111,7 +140,18 @@ class SystemTagsObjectMappingCollection implements ICollection { function childExists($tagId) { try { - return ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)); + $result = ($this->tagMapper->haveTag([$this->objectId], $this->objectType, $tagId, true)); + if ($this->isAdmin || !$result) { + return $result; + } + + // verify if user is allowed to see this tag + $tag = $this->tagManager->getTagsByIds($tagId); + $tag = current($tag); + if (!$tag->isUserVisible()) { + return false; + } + return true; } catch (\InvalidArgumentException $e) { throw new BadRequest('Invalid tag id', 0, $e); } catch (TagNotFoundException $e) { @@ -153,6 +193,7 @@ class SystemTagsObjectMappingCollection implements ICollection { $tag, $this->objectId, $this->objectType, + $this->isAdmin, $this->tagManager, $this->tagMapper ); diff --git a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php index 949c7df9fee..7b58d0e1fcc 100644 --- a/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php +++ b/apps/dav/lib/systemtag/systemtagsobjecttypecollection.php @@ -51,16 +51,25 @@ class SystemTagsObjectTypeCollection implements ICollection { private $tagMapper; /** + * Whether to return results only visible for admins + * + * @var bool + */ + private $isAdmin; + + /** * Constructor * * @param string $objectType object type + * @param bool $isAdmin whether to return results visible only for admins * @param ISystemTagManager $tagManager * @param ISystemTagObjectMapper $tagMapper */ - public function __construct($objectType, $tagManager, $tagMapper) { + public function __construct($objectType, $isAdmin, $tagManager, $tagMapper) { $this->tagManager = $tagManager; $this->tagMapper = $tagMapper; $this->objectType = $objectType; + $this->isAdmin = $isAdmin; } /** @@ -86,6 +95,7 @@ class SystemTagsObjectTypeCollection implements ICollection { return new SystemTagsObjectMappingCollection( $objectId, $this->objectType, + $this->isAdmin, $this->tagManager, $this->tagMapper ); diff --git a/apps/dav/lib/systemtag/systemtagsrelationscollection.php b/apps/dav/lib/systemtag/systemtagsrelationscollection.php index 7d3d9ed75b1..52d39b2b59c 100644 --- a/apps/dav/lib/systemtag/systemtagsrelationscollection.php +++ b/apps/dav/lib/systemtag/systemtagsrelationscollection.php @@ -32,12 +32,13 @@ class SystemTagsRelationsCollection extends SimpleCollection { /** * SystemTagsRelationsCollection constructor. * + * @param bool $isAdmin whether to return results visible only for admins * @param ISystemTagManager $tagManager * @param ISystemTagObjectMapper $tagMapper */ - public function __construct($tagManager, $tagMapper) { + public function __construct($isAdmin, $tagManager, $tagMapper) { $children = [ - new SystemTagsObjectTypeCollection('files', $tagManager, $tagMapper), + new SystemTagsObjectTypeCollection('files', $isAdmin, $tagManager, $tagMapper), ]; parent::__construct('root', $children); diff --git a/apps/dav/tests/unit/systemtag/systemtagmappingnode.php b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php index 14661302d47..7f2ff7d6616 100644 --- a/apps/dav/tests/unit/systemtag/systemtagmappingnode.php +++ b/apps/dav/tests/unit/systemtag/systemtagmappingnode.php @@ -25,12 +25,7 @@ use Sabre\DAV\Exception\NotFound; use OC\SystemTag\SystemTag; use OCP\SystemTag\TagNotFoundException; -class SystemTagMappingNode extends SystemTagNode { - - /** - * @var \OCA\DAV\SystemTag\SystemTagMappingNode - */ - private $node; +class SystemTagMappingNode extends \Test\TestCase { /** * @var \OCP\SystemTag\ISystemTagManager @@ -42,41 +37,85 @@ class SystemTagMappingNode extends SystemTagNode { */ 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, + public function getMappingNode($isAdmin = true, $tag = null) { + if ($tag === null) { + $tag = new SystemTag(1, 'Test', true, true); + } + return new \OCA\DAV\SystemTag\SystemTagMappingNode( + $tag, 123, 'files', + $isAdmin, $this->tagManager, $this->tagMapper ); } public function testGetters() { - parent::testGetters(); - $this->assertEquals(123, $this->node->getObjectId()); - $this->assertEquals('files', $this->node->getObjectType()); + $tag = new SystemTag(1, 'Test', true, false); + $node = $this->getMappingNode(true, $tag); + $this->assertEquals('1', $node->getName()); + $this->assertEquals($tag, $node->getSystemTag()); + $this->assertEquals(123, $node->getObjectId()); + $this->assertEquals('files', $node->getObjectType()); + } + + public function adminFlagProvider() { + return [[true], [false]]; } - public function testDeleteTag() { + /** + * @dataProvider adminFlagProvider + */ + public function testDeleteTag($isAdmin) { $this->tagManager->expects($this->never()) ->method('deleteTags'); $this->tagMapper->expects($this->once()) ->method('unassignTags') ->with(123, 'files', 1); - $this->node->delete(); + $this->getMappingNode($isAdmin)->delete(); + } + + public function tagNodeDeleteProviderPermissionException() { + return [ + [ + // cannot unassign invisible tag + new SystemTag(1, 'Original', false, true), + 'Sabre\DAV\Exception\NotFound', + ], + [ + // cannot unassign non-assignable tag + new SystemTag(1, 'Original', true, false), + 'Sabre\DAV\Exception\Forbidden', + ], + ]; + } + + /** + * @dataProvider tagNodeDeleteProviderPermissionException + */ + public function testDeleteTagExpectedException($tag, $expectedException) { + $this->tagManager->expects($this->never()) + ->method('deleteTags'); + $this->tagMapper->expects($this->never()) + ->method('unassignTags'); + + $thrown = null; + try { + $this->getMappingNode(false, $tag)->delete(); + } catch (\Exception $e) { + $thrown = $e; + } + + $this->assertInstanceOf($expectedException, $thrown); } /** @@ -88,6 +127,6 @@ class SystemTagMappingNode extends SystemTagNode { ->with(123, 'files', 1) ->will($this->throwException(new TagNotFoundException())); - $this->node->delete(); + $this->getMappingNode()->delete(); } } diff --git a/apps/dav/tests/unit/systemtag/systemtagnode.php b/apps/dav/tests/unit/systemtag/systemtagnode.php index 1407d2274f9..5184b74e5c8 100644 --- a/apps/dav/tests/unit/systemtag/systemtagnode.php +++ b/apps/dav/tests/unit/systemtag/systemtagnode.php @@ -32,46 +32,140 @@ 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); + protected function getTagNode($isAdmin = true, $tag = null) { + if ($tag === null) { + $tag = new SystemTag(1, 'Test', true, true); + } + return new \OCA\DAV\SystemTag\SystemTagNode( + $tag, + $isAdmin, + $this->tagManager + ); } - public function testGetters() { - $this->assertEquals('1', $this->node->getName()); - $this->assertEquals($this->tag, $this->node->getSystemTag()); + public function adminFlagProvider() { + return [[true], [false]]; + } + + /** + * @dataProvider adminFlagProvider + */ + public function testGetters($isAdmin) { + $tag = new SystemTag('1', 'Test', true, true); + $node = $this->getTagNode($isAdmin, $tag); + $this->assertEquals('1', $node->getName()); + $this->assertEquals($tag, $node->getSystemTag()); } /** * @expectedException Sabre\DAV\Exception\MethodNotAllowed */ public function testSetName() { - $this->node->setName('2'); + $this->getTagNode()->setName('2'); + } + + public function tagNodeProvider() { + return [ + // admin + [ + true, + new SystemTag(1, 'Original', true, true), + ['Renamed', true, true] + ], + [ + true, + new SystemTag(1, 'Original', true, true), + ['Original', false, false] + ], + // non-admin + [ + // renaming allowed + false, + new SystemTag(1, 'Original', true, true), + ['Rename', true, true] + ], + ]; } - public function testUpdateTag() { + /** + * @dataProvider tagNodeProvider + */ + public function testUpdateTag($isAdmin, $originalTag, $changedArgs) { $this->tagManager->expects($this->once()) ->method('updateTag') - ->with(1, 'Renamed', false, true); - $this->node->update('Renamed', false, true); + ->with(1, $changedArgs[0], $changedArgs[1], $changedArgs[2]); + $this->getTagNode($isAdmin, $originalTag) + ->update($changedArgs[0], $changedArgs[1], $changedArgs[2]); + } + + public function tagNodeProviderPermissionException() { + return [ + [ + // changing permissions not allowed + new SystemTag(1, 'Original', true, true), + ['Original', false, true], + 'Sabre\DAV\Exception\Forbidden', + ], + [ + // changing permissions not allowed + new SystemTag(1, 'Original', true, true), + ['Original', true, false], + 'Sabre\DAV\Exception\Forbidden', + ], + [ + // changing permissions not allowed + new SystemTag(1, 'Original', true, true), + ['Original', false, false], + 'Sabre\DAV\Exception\Forbidden', + ], + [ + // changing non-assignable not allowed + new SystemTag(1, 'Original', true, false), + ['Rename', true, false], + 'Sabre\DAV\Exception\Forbidden', + ], + [ + // changing non-assignable not allowed + new SystemTag(1, 'Original', true, false), + ['Original', true, true], + 'Sabre\DAV\Exception\Forbidden', + ], + [ + // invisible tag does not exist + new SystemTag(1, 'Original', false, false), + ['Rename', false, false], + 'Sabre\DAV\Exception\NotFound', + ], + ]; + } + + /** + * @dataProvider tagNodeProviderPermissionException + */ + public function testUpdateTagPermissionException($originalTag, $changedArgs, $expectedException = null) { + $this->tagManager->expects($this->never()) + ->method('updateTag'); + + $thrown = null; + + try { + $this->getTagNode(false, $originalTag) + ->update($changedArgs[0], $changedArgs[1], $changedArgs[2]); + } catch (\Exception $e) { + $thrown = $e; + } + + $this->assertInstanceOf($expectedException, $thrown); } /** @@ -82,7 +176,7 @@ class SystemTagNode extends \Test\TestCase { ->method('updateTag') ->with(1, 'Renamed', false, true) ->will($this->throwException(new TagAlreadyExistsException())); - $this->node->update('Renamed', false, true); + $this->getTagNode()->update('Renamed', false, true); } /** @@ -93,14 +187,48 @@ class SystemTagNode extends \Test\TestCase { ->method('updateTag') ->with(1, 'Renamed', false, true) ->will($this->throwException(new TagNotFoundException())); - $this->node->update('Renamed', false, true); + $this->getTagNode()->update('Renamed', false, true); } - public function testDeleteTag() { + /** + * @dataProvider adminFlagProvider + */ + public function testDeleteTag($isAdmin) { $this->tagManager->expects($this->once()) ->method('deleteTags') ->with('1'); - $this->node->delete(); + $this->getTagNode($isAdmin)->delete(); + } + + public function tagNodeDeleteProviderPermissionException() { + return [ + [ + // cannot delete invisible tag + new SystemTag(1, 'Original', false, true), + 'Sabre\DAV\Exception\NotFound', + ], + [ + // cannot delete non-assignable tag + new SystemTag(1, 'Original', true, false), + 'Sabre\DAV\Exception\Forbidden', + ], + ]; + } + + /** + * @dataProvider tagNodeDeleteProviderPermissionException + */ + public function testDeleteTagPermissionException($tag, $expectedException) { + $this->tagManager->expects($this->never()) + ->method('deleteTags'); + + try { + $this->getTagNode(false, $tag)->delete(); + } catch (\Exception $e) { + $thrown = $e; + } + + $this->assertInstanceOf($expectedException, $thrown); } /** @@ -111,6 +239,6 @@ class SystemTagNode extends \Test\TestCase { ->method('deleteTags') ->with('1') ->will($this->throwException(new TagNotFoundException())); - $this->node->delete(); + $this->getTagNode()->delete(); } } diff --git a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php index 4ed54cfef6f..cba943545af 100644 --- a/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php +++ b/apps/dav/tests/unit/systemtag/systemtagsbyidcollection.php @@ -28,11 +28,6 @@ use OCP\SystemTag\TagNotFoundException; class SystemTagsByIdCollection extends \Test\TestCase { /** - * @var \OCA\DAV\SystemTag\SystemTagsByIdCollection - */ - private $node; - - /** * @var \OCP\SystemTag\ISystemTagManager */ private $tagManager; @@ -41,33 +36,59 @@ class SystemTagsByIdCollection extends \Test\TestCase { parent::setUp(); $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); + } + + public function getNode($isAdmin = true) { + return new \OCA\DAV\SystemTag\SystemTagsByIdCollection($isAdmin, $this->tagManager); + } - $this->node = new \OCA\DAV\SystemTag\SystemTagsByIdCollection($this->tagManager); + public function adminFlagProvider() { + return [[true], [false]]; } /** * @expectedException Sabre\DAV\Exception\Forbidden */ public function testForbiddenCreateFile() { - $this->node->createFile('555'); + $this->getNode()->createFile('555'); } /** * @expectedException Sabre\DAV\Exception\Forbidden */ public function testForbiddenCreateDirectory() { - $this->node->createDirectory('789'); + $this->getNode()->createDirectory('789'); } - public function testGetChild() { - $tag = new SystemTag(123, 'Test', true, false); + public function getChildProvider() { + return [ + [ + true, + true, + ], + [ + true, + false, + ], + [ + false, + true, + ], + ]; + } + + /** + * @dataProvider getChildProvider + */ + public function testGetChild($isAdmin, $userVisible) { + $tag = new SystemTag(123, 'Test', $userVisible, false); $this->tagManager->expects($this->once()) ->method('getTagsByIds') ->with(['123']) ->will($this->returnValue([$tag])); - $childNode = $this->node->getChild('123'); + $childNode = $this->getNode($isAdmin)->getChild('123'); $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); $this->assertEquals('123', $childNode->getName()); @@ -83,7 +104,7 @@ class SystemTagsByIdCollection extends \Test\TestCase { ->with(['invalid']) ->will($this->throwException(new \InvalidArgumentException())); - $this->node->getChild('invalid'); + $this->getNode()->getChild('invalid'); } /** @@ -95,10 +116,43 @@ class SystemTagsByIdCollection extends \Test\TestCase { ->with(['444']) ->will($this->throwException(new TagNotFoundException())); - $this->node->getChild('444'); + $this->getNode()->getChild('444'); + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChildUserNotVisible() { + $tag = new SystemTag(123, 'Test', false, false); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['123']) + ->will($this->returnValue([$tag])); + + $this->getNode(false)->getChild('123'); } - public function testGetChildren() { + public function testGetChildrenAdmin() { + $tag1 = new SystemTag(123, 'One', true, false); + $tag2 = new SystemTag(456, 'Two', true, true); + + $this->tagManager->expects($this->once()) + ->method('getAllTags') + ->with(null) + ->will($this->returnValue([$tag1, $tag2])); + + $children = $this->getNode(true)->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 testGetChildrenNonAdmin() { $tag1 = new SystemTag(123, 'One', true, false); $tag2 = new SystemTag(456, 'Two', true, true); @@ -107,7 +161,7 @@ class SystemTagsByIdCollection extends \Test\TestCase { ->with(true) ->will($this->returnValue([$tag1, $tag2])); - $children = $this->node->getChildren(); + $children = $this->getNode(false)->getChildren(); $this->assertCount(2, $children); @@ -120,20 +174,34 @@ class SystemTagsByIdCollection extends \Test\TestCase { public function testGetChildrenEmpty() { $this->tagManager->expects($this->once()) ->method('getAllTags') - ->with(true) + ->with(null) ->will($this->returnValue([])); - $this->assertCount(0, $this->node->getChildren()); + $this->assertCount(0, $this->getNode()->getChildren()); + } + + public function childExistsProvider() { + return [ + // admins, always visible + [true, true, true], + [true, false, true], + // non-admins, depends on flag + [false, true, true], + [false, false, false], + ]; } - public function testChildExists() { - $tag = new SystemTag(123, 'One', true, false); + /** + * @dataProvider childExistsProvider + */ + public function testChildExists($isAdmin, $userVisible, $expectedResult) { + $tag = new SystemTag(123, 'One', $userVisible, false); $this->tagManager->expects($this->once()) ->method('getTagsByIds') ->with(['123']) ->will($this->returnValue([$tag])); - $this->assertTrue($this->node->childExists('123')); + $this->assertEquals($expectedResult, $this->getNode($isAdmin)->childExists('123')); } public function testChildExistsNotFound() { @@ -142,7 +210,7 @@ class SystemTagsByIdCollection extends \Test\TestCase { ->with(['123']) ->will($this->throwException(new TagNotFoundException())); - $this->assertFalse($this->node->childExists('123')); + $this->assertFalse($this->getNode()->childExists('123')); } /** @@ -154,6 +222,6 @@ class SystemTagsByIdCollection extends \Test\TestCase { ->with(['invalid']) ->will($this->throwException(new \InvalidArgumentException())); - $this->node->childExists('invalid'); + $this->getNode()->childExists('invalid'); } } diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php index 07998082c3b..df97acd846b 100644 --- a/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php +++ b/apps/dav/tests/unit/systemtag/systemtagsobjectmappingcollection.php @@ -28,11 +28,6 @@ use OCP\SystemTag\TagNotFoundException; class SystemTagsObjectMappingCollection extends \Test\TestCase { /** - * @var \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection - */ - private $node; - - /** * @var \OCP\SystemTag\ISystemTagManager */ private $tagManager; @@ -47,21 +42,72 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->tagManager = $this->getMock('\OCP\SystemTag\ISystemTagManager'); $this->tagMapper = $this->getMock('\OCP\SystemTag\ISystemTagObjectMapper'); + } - $this->node = new \OCA\DAV\SystemTag\SystemTagsObjectMappingCollection ( + public function getNode($isAdmin = true) { + return new \OCA\DAV\SystemTag\SystemTagsObjectMappingCollection ( 111, 'files', + $isAdmin, $this->tagManager, $this->tagMapper ); } - public function testAssignTag() { + public function testAssignTagAsAdmin() { + $this->tagManager->expects($this->never()) + ->method('getTagsByIds'); + $this->tagMapper->expects($this->once()) + ->method('assignTags') + ->with(111, 'files', '555'); + + $this->getNode(true)->createFile('555'); + } + + public function testAssignTagAsUser() { + $tag = new SystemTag('1', 'Test', true, true); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with('555') + ->will($this->returnValue([$tag])); $this->tagMapper->expects($this->once()) ->method('assignTags') ->with(111, 'files', '555'); - $this->node->createFile('555'); + $this->getNode(false)->createFile('555'); + } + + public function permissionsProvider() { + return [ + // invisible, tag does not exist for user + [false, true, '\Sabre\DAV\Exception\PreconditionFailed'], + // visible but static, cannot assign tag + [true, false, '\Sabre\DAV\Exception\Forbidden'], + ]; + } + + /** + * @dataProvider permissionsProvider + */ + public function testAssignTagAsUserNoPermission($userVisible, $userAssignable, $expectedException) { + $tag = new SystemTag('1', 'Test', $userVisible, $userAssignable); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with('555') + ->will($this->returnValue([$tag])); + $this->tagMapper->expects($this->never()) + ->method('assignTags'); + + $thrown = null; + try { + $this->getNode(false)->createFile('555'); + } catch (\Exception $e) { + $thrown = $e; + } + + $this->assertInstanceOf($expectedException, $thrown); } /** @@ -73,18 +119,38 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with(111, 'files', '555') ->will($this->throwException(new TagNotFoundException())); - $this->node->createFile('555'); + $this->getNode()->createFile('555'); } /** * @expectedException Sabre\DAV\Exception\Forbidden */ public function testForbiddenCreateDirectory() { - $this->node->createDirectory('789'); + $this->getNode()->createDirectory('789'); } - public function testGetChild() { - $tag = new SystemTag(555, 'TheTag', true, false); + public function getChildProvider() { + return [ + [ + true, + true, + ], + [ + true, + false, + ], + [ + false, + true, + ], + ]; + } + + /** + * @dataProvider getChildProvider + */ + public function testGetChild($isAdmin, $userVisible) { + $tag = new SystemTag(555, 'TheTag', $userVisible, false); $this->tagMapper->expects($this->once()) ->method('haveTag') @@ -96,13 +162,32 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with(['555']) ->will($this->returnValue(['555' => $tag])); - $childNode = $this->node->getChild('555'); + $childNode = $this->getNode($isAdmin)->getChild('555'); $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagNode', $childNode); $this->assertEquals('555', $childNode->getName()); } /** + * @expectedException \Sabre\DAV\Exception\NotFound + */ + public function testGetChildUserNonVisible() { + $tag = new SystemTag(555, 'TheTag', false, false); + + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '555', true) + ->will($this->returnValue(true)); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['555']) + ->will($this->returnValue(['555' => $tag])); + + $this->getNode(false)->getChild('555'); + } + + /** * @expectedException Sabre\DAV\Exception\NotFound */ public function testGetChildRelationNotFound() { @@ -111,7 +196,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with([111], 'files', '777') ->will($this->returnValue(false)); - $this->node->getChild('777'); + $this->getNode()->getChild('777'); } /** @@ -123,7 +208,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with([111], 'files', 'badid') ->will($this->throwException(new \InvalidArgumentException())); - $this->node->getChild('badid'); + $this->getNode()->getChild('badid'); } /** @@ -135,24 +220,61 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with([111], 'files', '777') ->will($this->throwException(new TagNotFoundException())); - $this->node->getChild('777'); + $this->getNode()->getChild('777'); + } + + public function testGetChildrenAsAdmin() { + $tag1 = new SystemTag(555, 'TagOne', true, false); + $tag2 = new SystemTag(556, 'TagTwo', true, true); + $tag3 = new SystemTag(557, 'InvisibleTag', false, true); + + $this->tagMapper->expects($this->once()) + ->method('getTagIdsForObjects') + ->with([111], 'files') + ->will($this->returnValue(['111' => ['555', '556', '557']])); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with(['555', '556', '557']) + ->will($this->returnValue(['555' => $tag1, '556' => $tag2, '557' => $tag3])); + + $children = $this->getNode(true)->getChildren(); + + $this->assertCount(3, $children); + + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[0]); + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[1]); + $this->assertInstanceOf('\OCA\DAV\SystemTag\SystemTagMappingNode', $children[2]); + + $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()); + + $this->assertEquals(111, $children[2]->getObjectId()); + $this->assertEquals('files', $children[2]->getObjectType()); + $this->assertEquals($tag3, $children[2]->getSystemTag()); } - public function testGetChildren() { + public function testGetChildrenAsUser() { $tag1 = new SystemTag(555, 'TagOne', true, false); $tag2 = new SystemTag(556, 'TagTwo', true, true); + $tag3 = new SystemTag(557, 'InvisibleTag', false, true); $this->tagMapper->expects($this->once()) ->method('getTagIdsForObjects') ->with([111], 'files') - ->will($this->returnValue(['111' => ['555', '556']])); + ->will($this->returnValue(['111' => ['555', '556', '557']])); $this->tagManager->expects($this->once()) ->method('getTagsByIds') - ->with(['555', '556']) - ->will($this->returnValue(['555' => $tag1, '666' => $tag2])); + ->with(['555', '556', '557']) + ->will($this->returnValue(['555' => $tag1, '556' => $tag2, '557' => $tag3])); - $children = $this->node->getChildren(); + $children = $this->getNode(false)->getChildren(); $this->assertCount(2, $children); @@ -168,13 +290,45 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { $this->assertEquals($tag2, $children[1]->getSystemTag()); } - public function testChildExists() { + public function testChildExistsAsAdmin() { $this->tagMapper->expects($this->once()) ->method('haveTag') ->with([111], 'files', '555') ->will($this->returnValue(true)); - $this->assertTrue($this->node->childExists('555')); + $this->assertTrue($this->getNode(true)->childExists('555')); + } + + public function testChildExistsWithVisibleTagAsUser() { + $tag = new SystemTag(555, 'TagOne', true, false); + + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '555') + ->will($this->returnValue(true)); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with('555') + ->will($this->returnValue([$tag])); + + $this->assertTrue($this->getNode(false)->childExists('555')); + } + + public function testChildExistsWithInvisibleTagAsUser() { + $tag = new SystemTag(555, 'TagOne', false, false); + + $this->tagMapper->expects($this->once()) + ->method('haveTag') + ->with([111], 'files', '555') + ->will($this->returnValue(true)); + + $this->tagManager->expects($this->once()) + ->method('getTagsByIds') + ->with('555') + ->will($this->returnValue([$tag])); + + $this->assertFalse($this->getNode(false)->childExists('555')); } public function testChildExistsNotFound() { @@ -183,7 +337,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with([111], 'files', '555') ->will($this->returnValue(false)); - $this->assertFalse($this->node->childExists('555')); + $this->assertFalse($this->getNode()->childExists('555')); } public function testChildExistsTagNotFound() { @@ -192,7 +346,7 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with([111], 'files', '555') ->will($this->throwException(new TagNotFoundException())); - $this->assertFalse($this->node->childExists('555')); + $this->assertFalse($this->getNode()->childExists('555')); } /** @@ -204,24 +358,24 @@ class SystemTagsObjectMappingCollection extends \Test\TestCase { ->with([111], 'files', '555') ->will($this->throwException(new \InvalidArgumentException())); - $this->node->childExists('555'); + $this->getNode()->childExists('555'); } /** * @expectedException Sabre\DAV\Exception\Forbidden */ public function testDelete() { - $this->node->delete(); + $this->getNode()->delete(); } /** * @expectedException Sabre\DAV\Exception\Forbidden */ public function testSetName() { - $this->node->setName('somethingelse'); + $this->getNode()->setName('somethingelse'); } public function testGetName() { - $this->assertEquals('111', $this->node->getName()); + $this->assertEquals('111', $this->getNode()->getName()); } } diff --git a/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php index ba63fad39aa..2d343f4790a 100644 --- a/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php +++ b/apps/dav/tests/unit/systemtag/systemtagsobjecttypecollection.php @@ -46,6 +46,7 @@ class SystemTagsObjectTypeCollection extends \Test\TestCase { $this->node = new \OCA\DAV\SystemTag\SystemTagsObjectTypeCollection( 'files', + true, $this->tagManager, $this->tagMapper ); |