Added oc:tags and oc:favorites in PROPFIND response. It is possible to update them with PROPPATCH. These properties are optional which means they need to be requested explicitlytags/v8.0.0alpha1
@@ -53,6 +53,7 @@ $server->subscribeEvent('beforeMethod', function () use ($server, $objectTree) { | |||
$rootDir = new OC_Connector_Sabre_Directory($view, $rootInfo); | |||
$objectTree->init($rootDir, $view, $mountManager); | |||
$server->addPlugin(new \OC\Connector\Sabre\TagsPlugin($objectTree, \OC::$server->getTagManager())); | |||
$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin($view)); | |||
}, 30); // priority 30: after auth (10) and acl(20), before lock(50) and handling the request | |||
@@ -21,9 +21,18 @@ | |||
* | |||
*/ | |||
use OC\Connector\Sabre\TagList; | |||
class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node | |||
implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota { | |||
/** | |||
* Cached directory content | |||
* | |||
* @var \OCP\FileInfo[] | |||
*/ | |||
private $dirContent; | |||
/** | |||
* Creates a new file in the directory | |||
* | |||
@@ -132,19 +141,34 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node | |||
return $node; | |||
} | |||
/** | |||
* Return the directory content as fileinfo objects | |||
* | |||
* @return \OCP\FileInfo[] | |||
*/ | |||
public function getDirectoryContent() { | |||
} | |||
/** | |||
* Returns an array with all the child nodes | |||
* | |||
* @return \Sabre\DAV\INode[] | |||
*/ | |||
public function getChildren() { | |||
if (!is_null($this->dirContent)) { | |||
return $this->dirContent; | |||
} | |||
$folderContent = $this->fileView->getDirectoryContent($this->path); | |||
$folder_content = $this->fileView->getDirectoryContent($this->path); | |||
$properties = array(); | |||
$paths = array(); | |||
foreach($folder_content as $info) { | |||
$paths[] = $this->path.'/'.$info['name']; | |||
$properties[$this->path.'/'.$info['name']][self::GETETAG_PROPERTYNAME] = '"' . $info['etag'] . '"'; | |||
foreach($folderContent as $info) { | |||
$name = $info->getName(); | |||
$paths[] = $this->path . '/' . $name; | |||
$properties[$this->path.'/' . $name][self::GETETAG_PROPERTYNAME] = '"' . $info->getEtag() . '"'; | |||
} | |||
// TODO: move this to a beforeGetPropertiesForPath event to pre-cache properties | |||
// TODO: only fetch the requested properties | |||
if(count($paths)>0) { | |||
// | |||
// the number of arguments within IN conditions are limited in most databases | |||
@@ -169,12 +193,13 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node | |||
} | |||
$nodes = array(); | |||
foreach($folder_content as $info) { | |||
foreach($folderContent as $info) { | |||
$node = $this->getChild($info->getName(), $info); | |||
$node->setPropertyCache($properties[$this->path.'/'.$info['name']]); | |||
$node->setPropertyCache($properties[$this->path . '/' . $info->getName()]); | |||
$nodes[] = $node; | |||
} | |||
return $nodes; | |||
$this->dirContent = $nodes; | |||
return $this->dirContent; | |||
} | |||
/** |
@@ -1,5 +1,7 @@ | |||
<?php | |||
use Sabre\DAV\URLUtil; | |||
use OC\Connector\Sabre\TagList; | |||
/** | |||
* ownCloud | |||
@@ -226,6 +228,15 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I | |||
return $props; | |||
} | |||
/** | |||
* Returns the cache's file id | |||
* | |||
* @return int | |||
*/ | |||
public function getId() { | |||
return $this->info->getId(); | |||
} | |||
/** | |||
* @return string|null | |||
*/ |
@@ -144,6 +144,13 @@ class OC_Connector_Sabre_Server extends Sabre\DAV\Server { | |||
$path = rtrim($path,'/'); | |||
// This event allows people to intercept these requests early on in the | |||
// process. | |||
// | |||
// We're not doing anything with the result, but this can be helpful to | |||
// pre-fetch certain expensive live properties. | |||
$this->broadCastEvent('beforeGetPropertiesForPath', array($path, $propertyNames, $depth)); | |||
$returnPropertyList = array(); | |||
$parentNode = $this->tree->getNodeForPath($path); |
@@ -0,0 +1,102 @@ | |||
<?php | |||
/** | |||
* ownCloud | |||
* | |||
* @author Vincent Petry | |||
* @copyright 2014 Vincent Petry <pvince81@owncloud.com> | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
namespace OC\Connector\Sabre; | |||
use Sabre\DAV; | |||
/** | |||
* TagList property | |||
* | |||
* This property contains multiple "tag" elements, each containing a tag name. | |||
*/ | |||
class TagList extends DAV\Property { | |||
const NS_OWNCLOUD = 'http://owncloud.org/ns'; | |||
/** | |||
* tags | |||
* | |||
* @var array | |||
*/ | |||
private $tags; | |||
/** | |||
* @param array $tags | |||
*/ | |||
public function __construct(array $tags) { | |||
$this->tags = $tags; | |||
} | |||
/** | |||
* Returns the tags | |||
* | |||
* @return array | |||
*/ | |||
public function getTags() { | |||
return $this->tags; | |||
} | |||
/** | |||
* Serializes this property. | |||
* | |||
* @param DAV\Server $server | |||
* @param \DOMElement $dom | |||
* @return void | |||
*/ | |||
public function serialize(DAV\Server $server,\DOMElement $dom) { | |||
$prefix = $server->xmlNamespaces[self::NS_OWNCLOUD]; | |||
foreach($this->tags as $tag) { | |||
$elem = $dom->ownerDocument->createElement($prefix . ':tag'); | |||
$elem->appendChild($dom->ownerDocument->createTextNode($tag)); | |||
$dom->appendChild($elem); | |||
} | |||
} | |||
/** | |||
* Unserializes this property from a DOM Element | |||
* | |||
* This method returns an instance of this class. | |||
* It will only decode tag values. | |||
* | |||
* @param \DOMElement $dom | |||
* @return DAV\Property\TagList | |||
*/ | |||
static function unserialize(\DOMElement $dom) { | |||
$tags = array(); | |||
foreach($dom->childNodes as $child) { | |||
if (DAV\XMLUtil::toClarkNotation($child)==='{' . self::NS_OWNCLOUD . '}tag') { | |||
$tags[] = $child->textContent; | |||
} | |||
} | |||
return new self($tags); | |||
} | |||
} |
@@ -0,0 +1,289 @@ | |||
<?php | |||
namespace OC\Connector\Sabre; | |||
/** | |||
* ownCloud | |||
* | |||
* @author Vincent Petry | |||
* @copyright 2014 Vincent Petry <pvince81@owncloud.com> | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |||
* | |||
* You should have received a copy of the GNU Affero General Public | |||
* License along with this library. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
class TagsPlugin extends \Sabre\DAV\ServerPlugin | |||
{ | |||
// namespace | |||
const NS_OWNCLOUD = 'http://owncloud.org/ns'; | |||
const TAGS_PROPERTYNAME = '{' . self::NS_OWNCLOUD . '}tags'; | |||
const FAVORITE_PROPERTYNAME = '{' . self::NS_OWNCLOUD . '}favorite'; | |||
const TAG_FAVORITE = '_$!<Favorite>!$_'; | |||
/** | |||
* Reference to main server object | |||
* | |||
* @var \Sabre\DAV\Server | |||
*/ | |||
private $server; | |||
/** | |||
* @var \OCP\ITagManager | |||
*/ | |||
private $tagManager; | |||
/** | |||
* @var \OCP\ITags | |||
*/ | |||
private $tagger; | |||
/** | |||
* Array of file id to tags array | |||
* The null value means the cache wasn't initialized. | |||
* | |||
* @var array | |||
*/ | |||
private $cachedTags; | |||
/** | |||
* @param \OCP\ITagManager $tagManager tag manager | |||
*/ | |||
public function __construct(\Sabre\DAV\ObjectTree $objectTree, \OCP\ITagManager $tagManager) { | |||
$this->objectTree = $objectTree; | |||
$this->tagManager = $tagManager; | |||
$this->tagger = null; | |||
$this->cachedTags = null; | |||
} | |||
/** | |||
* 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->propertyMap[self::TAGS_PROPERTYNAME] = 'OC\\Connector\\Sabre\\TagList'; | |||
$this->server = $server; | |||
$this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties')); | |||
$this->server->subscribeEvent('beforeGetPropertiesForPath', array($this, 'beforeGetPropertiesForPath')); | |||
$this->server->subscribeEvent('updateProperties', array($this, 'updateProperties')); | |||
} | |||
/** | |||
* Searches and removes a value from the given array | |||
* | |||
* @param array $requestedProps | |||
* @param string $propName to remove | |||
* @return boolean true if the property was present, false otherwise | |||
*/ | |||
private function findAndRemoveProperty(&$requestedProps, $propName) { | |||
$index = array_search($propName, $requestedProps); | |||
if ($index !== false) { | |||
unset($requestedProps[$index]); | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Returns the tagger | |||
* | |||
* @return \OCP\ITags tagger | |||
*/ | |||
private function getTagger() { | |||
if (!$this->tagger) { | |||
$this->tagger = $this->tagManager->load('files'); | |||
} | |||
return $this->tagger; | |||
} | |||
/** | |||
* Returns tags and favorites. | |||
* | |||
* @param integer $fileId file id | |||
* @return array list($tags, $favorite) with $tags as tag array | |||
* and $favorite is a boolean whether the file was favorited | |||
*/ | |||
private function getTagsAndFav($fileId) { | |||
$isFav = false; | |||
$tags = $this->getTags($fileId); | |||
if ($tags) { | |||
$favPos = array_search(self::TAG_FAVORITE, $tags); | |||
if ($favPos !== false) { | |||
$isFav = true; | |||
unset($tags[$favPos]); | |||
} | |||
} | |||
return array($tags, $isFav); | |||
} | |||
/** | |||
* Returns tags for the given file id | |||
* | |||
* @param integer $fileId file id | |||
* @return array list of tags for that file | |||
*/ | |||
private function getTags($fileId) { | |||
if (isset($this->cachedTags[$fileId])) { | |||
return $this->cachedTags[$fileId]; | |||
} else { | |||
$tags = $this->getTagger()->getTagsForObjects(array($fileId)); | |||
if ($tags) { | |||
return current($tags); | |||
} | |||
} | |||
return null; | |||
} | |||
/** | |||
* Updates the tags of the given file id | |||
* | |||
* @param int $fileId | |||
* @param array $tags array of tag strings | |||
*/ | |||
private function updateTags($fileId, $tags) { | |||
$tagger = $this->getTagger(); | |||
$currentTags = $this->getTags($fileId); | |||
$newTags = array_diff($tags, $currentTags); | |||
foreach ($newTags as $tag) { | |||
if ($tag === self::TAG_FAVORITE) { | |||
continue; | |||
} | |||
$tagger->tagAs($fileId, $tag); | |||
} | |||
$deletedTags = array_diff($currentTags, $tags); | |||
foreach ($deletedTags as $tag) { | |||
if ($tag === self::TAG_FAVORITE) { | |||
continue; | |||
} | |||
$tagger->unTag($fileId, $tag); | |||
} | |||
} | |||
/** | |||
* Pre-fetch tags info | |||
* | |||
* @param string $path | |||
* @param array $requestedProperties | |||
* @param integer $depth | |||
* @return void | |||
*/ | |||
public function beforeGetPropertiesForPath( | |||
$path, | |||
array $requestedProperties, | |||
$depth | |||
) { | |||
$node = $this->objectTree->getNodeForPath($path); | |||
if (!($node instanceof \OC_Connector_Sabre_Directory)) { | |||
return; | |||
} | |||
if ($this->findAndRemoveProperty($requestedProperties, self::TAGS_PROPERTYNAME) | |||
|| $this->findAndRemoveProperty($requestedProperties, self::FAVORITE_PROPERTYNAME) | |||
) { | |||
$fileIds = array(); | |||
// note: pre-fetching only supported for depth <= 1 | |||
$folderContent = $node->getChildren(); | |||
// TODO: refactor somehow with the similar array that is created | |||
// in getChildren() | |||
foreach ($folderContent as $info) { | |||
$fileIds[] = $info->getId(); | |||
} | |||
$tags = $this->getTagger()->getTagsForObjects($fileIds); | |||
if ($tags) { | |||
$this->cachedTags = $tags; | |||
} | |||
} | |||
} | |||
/** | |||
* Adds tags and favorites properties to the response, | |||
* if requested. | |||
* | |||
* @param string $path | |||
* @param \Sabre\DAV\INode $node | |||
* @param array $requestedProperties | |||
* @param array $returnedProperties | |||
* @return void | |||
*/ | |||
public function beforeGetProperties( | |||
$path, | |||
\Sabre\DAV\INode $node, | |||
array &$requestedProperties, | |||
array &$returnedProperties | |||
) { | |||
if (!($node instanceof \OC_Connector_Sabre_Node)) { | |||
return; | |||
} | |||
$tags = null; | |||
$isFav = null; | |||
if ($this->findAndRemoveProperty($requestedProperties, self::TAGS_PROPERTYNAME)) { | |||
list($tags, $isFav) = $this->getTagsAndFav($node->getId()); | |||
$returnedProperties[200][self::TAGS_PROPERTYNAME] = new TagList($tags); | |||
} | |||
if ($this->findAndRemoveProperty($requestedProperties, self::FAVORITE_PROPERTYNAME)) { | |||
if (is_null($tags)) { | |||
list($tags, $isFav) = $this->getTagsAndFav($node->getId()); | |||
} | |||
$returnedProperties[200][self::FAVORITE_PROPERTYNAME] = $isFav; | |||
} | |||
} | |||
/** | |||
* Updates tags and favorites properties, if applicable. | |||
* | |||
* @param string $path | |||
* @param \Sabre\DAV\INode $node | |||
* @param array $requestedProperties | |||
* @param array $returnedProperties | |||
* @return bool success status | |||
*/ | |||
public function updateProperties(array &$properties, array &$result, \Sabre\DAV\INode $node) { | |||
if (!($node instanceof \OC_Connector_Sabre_Node)) { | |||
return; | |||
} | |||
$fileId = $node->getId(); | |||
if (isset($properties[self::TAGS_PROPERTYNAME])) { | |||
$tagsProp = $properties[self::TAGS_PROPERTYNAME]; | |||
unset($properties[self::TAGS_PROPERTYNAME]); | |||
$this->updateTags($fileId, $tagsProp->getTags()); | |||
$result[200][self::TAGS_PROPERTYNAME] = new TagList($tagsProp->getTags()); | |||
} | |||
if (isset($properties[self::FAVORITE_PROPERTYNAME])) { | |||
$favState = $properties[self::FAVORITE_PROPERTYNAME]; | |||
unset($properties[self::FAVORITE_PROPERTYNAME]); | |||
if ((int)$favState === 1 || $favState === 'true') { | |||
$favState = true; | |||
$this->getTagger()->tagAs($fileId, self::TAG_FAVORITE); | |||
} else { | |||
$favState = false; | |||
$this->getTagger()->unTag($fileId, self::TAG_FAVORITE); | |||
} | |||
$result[200][self::FAVORITE_PROPERTYNAME] = $favState; | |||
} | |||
return true; | |||
} | |||
} |
@@ -101,4 +101,58 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase { | |||
$dir = $this->getRootDir(); | |||
$dir->delete(); | |||
} | |||
public function testGetChildren() { | |||
$info1 = $this->getMockBuilder('OC\Files\FileInfo') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$info2 = $this->getMockBuilder('OC\Files\FileInfo') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$info1->expects($this->any()) | |||
->method('getName') | |||
->will($this->returnValue('first')); | |||
$info1->expects($this->any()) | |||
->method('getEtag') | |||
->will($this->returnValue('abc')); | |||
$info2->expects($this->any()) | |||
->method('getName') | |||
->will($this->returnValue('second')); | |||
$info2->expects($this->any()) | |||
->method('getEtag') | |||
->will($this->returnValue('def')); | |||
$this->view->expects($this->once()) | |||
->method('getDirectoryContent') | |||
->with('') | |||
->will($this->returnValue(array($info1, $info2))); | |||
$this->view->expects($this->any()) | |||
->method('getRelativePath') | |||
->will($this->returnValue('')); | |||
$dir = new OC_Connector_Sabre_Directory($this->view, $this->info); | |||
$nodes = $dir->getChildren(); | |||
$this->assertEquals(2, count($nodes)); | |||
// calling a second time just returns the cached values, | |||
// does not call getDirectoryContents again | |||
$nodes = $dir->getChildren(); | |||
$properties = array('testprop', OC_Connector_Sabre_Node::GETETAG_PROPERTYNAME); | |||
$this->assertEquals(2, count($nodes)); | |||
$this->assertEquals( | |||
array( | |||
OC_Connector_Sabre_Node::GETETAG_PROPERTYNAME => '"abc"' | |||
), | |||
$nodes[0]->getProperties($properties) | |||
); | |||
$this->assertEquals( | |||
array( | |||
OC_Connector_Sabre_Node::GETETAG_PROPERTYNAME => '"def"' | |||
), | |||
$nodes[1]->getProperties($properties) | |||
); | |||
} | |||
} |
@@ -0,0 +1,314 @@ | |||
<?php | |||
namespace Tests\Connector\Sabre; | |||
/** | |||
* Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> | |||
* This file is licensed under the Affero General Public License version 3 or | |||
* later. | |||
* See the COPYING-README file. | |||
*/ | |||
class TagsPlugin extends \Test\TestCase { | |||
const TAGS_PROPERTYNAME = \OC\Connector\Sabre\TagsPlugin::TAGS_PROPERTYNAME; | |||
const FAVORITE_PROPERTYNAME = \OC\Connector\Sabre\TagsPlugin::FAVORITE_PROPERTYNAME; | |||
const TAG_FAVORITE = \OC\Connector\Sabre\TagsPlugin::TAG_FAVORITE; | |||
/** | |||
* @var \Sabre\DAV\Server | |||
*/ | |||
private $server; | |||
/** | |||
* @var \Sabre\DAV\ObjectTree | |||
*/ | |||
private $tree; | |||
/** | |||
* @var \OCP\ITagManager | |||
*/ | |||
private $tagManager; | |||
/** | |||
* @var \OCP\ITags | |||
*/ | |||
private $tagger; | |||
/** | |||
* @var \OC\Connector\Sabre\TagsPlugin | |||
*/ | |||
private $plugin; | |||
public function setUp() { | |||
parent::setUp(); | |||
$this->server = new \Sabre\DAV\Server(); | |||
$this->tree = $this->getMockBuilder('\Sabre\DAV\ObjectTree') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->tagger = $this->getMock('\OCP\ITags'); | |||
$this->tagManager = $this->getMock('\OCP\ITagManager'); | |||
$this->tagManager->expects($this->any()) | |||
->method('load') | |||
->with('files') | |||
->will($this->returnValue($this->tagger)); | |||
$this->plugin = new \OC\Connector\Sabre\TagsPlugin($this->tree, $this->tagManager); | |||
$this->plugin->initialize($this->server); | |||
} | |||
/** | |||
* @dataProvider tagsGetPropertiesDataProvider | |||
*/ | |||
public function testGetProperties($tags, $requestedProperties, $expectedProperties) { | |||
$node = $this->getMockBuilder('\OC_Connector_Sabre_Node') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$node->expects($this->any()) | |||
->method('getId') | |||
->will($this->returnValue(123)); | |||
$expectedCallCount = 0; | |||
if (count($requestedProperties) > 0) { | |||
$expectedCallCount = 1; | |||
} | |||
$this->tagger->expects($this->exactly($expectedCallCount)) | |||
->method('getTagsForObjects') | |||
->with($this->equalTo(array(123))) | |||
->will($this->returnValue(array(123 => $tags))); | |||
$returnedProperties = array(); | |||
$this->plugin->beforeGetProperties( | |||
'', | |||
$node, | |||
$requestedProperties, | |||
$returnedProperties | |||
); | |||
$this->assertEquals($expectedProperties, $returnedProperties); | |||
} | |||
/** | |||
* @dataProvider tagsGetPropertiesDataProvider | |||
*/ | |||
public function testPreloadThenGetProperties($tags, $requestedProperties, $expectedProperties) { | |||
$node1 = $this->getMockBuilder('\OC_Connector_Sabre_File') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$node1->expects($this->any()) | |||
->method('getId') | |||
->will($this->returnValue(111)); | |||
$node2 = $this->getMockBuilder('\OC_Connector_Sabre_File') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$node2->expects($this->any()) | |||
->method('getId') | |||
->will($this->returnValue(222)); | |||
$expectedCallCount = 0; | |||
if (count($requestedProperties) > 0) { | |||
// this guarantees that getTagsForObjects | |||
// is only called once and then the tags | |||
// are cached | |||
$expectedCallCount = 1; | |||
} | |||
$node = $this->getMockBuilder('\OC_Connector_Sabre_Directory') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$node->expects($this->any()) | |||
->method('getId') | |||
->will($this->returnValue(123)); | |||
$node->expects($this->exactly($expectedCallCount)) | |||
->method('getChildren') | |||
->will($this->returnValue(array($node1, $node2))); | |||
$this->tree->expects($this->once()) | |||
->method('getNodeForPath') | |||
->with('/subdir') | |||
->will($this->returnValue($node)); | |||
$this->tagger->expects($this->exactly($expectedCallCount)) | |||
->method('getTagsForObjects') | |||
->with($this->equalTo(array(111, 222))) | |||
->will($this->returnValue( | |||
array( | |||
111 => $tags, | |||
123 => $tags | |||
) | |||
)); | |||
$returnedProperties = array(); | |||
$this->plugin->beforeGetPropertiesForPath( | |||
'/subdir', | |||
$requestedProperties, | |||
1 | |||
); | |||
$this->plugin->beforeGetProperties( | |||
'/subdir/test.txt', | |||
$node1, | |||
$requestedProperties, | |||
$returnedProperties | |||
); | |||
$this->assertEquals($expectedProperties, $returnedProperties); | |||
} | |||
function tagsGetPropertiesDataProvider() { | |||
return array( | |||
// request both, receive both | |||
array( | |||
array('tag1', 'tag2', self::TAG_FAVORITE), | |||
array(self::TAGS_PROPERTYNAME, self::FAVORITE_PROPERTYNAME), | |||
array( | |||
200 => array( | |||
self::TAGS_PROPERTYNAME => new \OC\Connector\Sabre\TagList(array('tag1', 'tag2')), | |||
self::FAVORITE_PROPERTYNAME => true, | |||
) | |||
) | |||
), | |||
// request tags alone | |||
array( | |||
array('tag1', 'tag2', self::TAG_FAVORITE), | |||
array(self::TAGS_PROPERTYNAME), | |||
array( | |||
200 => array( | |||
self::TAGS_PROPERTYNAME => new \OC\Connector\Sabre\TagList(array('tag1', 'tag2')), | |||
) | |||
) | |||
), | |||
// request fav alone | |||
array( | |||
array('tag1', 'tag2', self::TAG_FAVORITE), | |||
array(self::FAVORITE_PROPERTYNAME), | |||
array( | |||
200 => array( | |||
self::FAVORITE_PROPERTYNAME => true, | |||
) | |||
) | |||
), | |||
// request none | |||
array( | |||
array('tag1', 'tag2', self::TAG_FAVORITE), | |||
array(), | |||
array(), | |||
), | |||
// request both with none set, receive both | |||
array( | |||
array(), | |||
array(self::TAGS_PROPERTYNAME, self::FAVORITE_PROPERTYNAME), | |||
array( | |||
200 => array( | |||
self::TAGS_PROPERTYNAME => new \OC\Connector\Sabre\TagList(array()), | |||
self::FAVORITE_PROPERTYNAME => false, | |||
) | |||
) | |||
), | |||
); | |||
} | |||
public function testUpdateTags() { | |||
// this test will replace the existing tags "tagremove" with "tag1" and "tag2" | |||
// and keep "tagkeep" | |||
$node = $this->getMockBuilder('\OC_Connector_Sabre_Node') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$node->expects($this->any()) | |||
->method('getId') | |||
->will($this->returnValue(123)); | |||
$this->tagger->expects($this->at(0)) | |||
->method('getTagsForObjects') | |||
->with($this->equalTo(array(123))) | |||
->will($this->returnValue(array(123 => array('tagkeep', 'tagremove', self::TAG_FAVORITE)))); | |||
// then tag as tag1 and tag2 | |||
$this->tagger->expects($this->at(1)) | |||
->method('tagAs') | |||
->with(123, 'tag1'); | |||
$this->tagger->expects($this->at(2)) | |||
->method('tagAs') | |||
->with(123, 'tag2'); | |||
// it will untag tag3 | |||
$this->tagger->expects($this->at(3)) | |||
->method('unTag') | |||
->with(123, 'tagremove'); | |||
// properties to set | |||
$properties = array( | |||
self::TAGS_PROPERTYNAME => new \OC\Connector\Sabre\TagList(array('tag1', 'tag2', 'tagkeep')) | |||
); | |||
$result = array(); | |||
$this->plugin->updateProperties( | |||
$properties, | |||
$result, | |||
$node | |||
); | |||
// all requested properties removed, as they were processed already | |||
$this->assertEmpty($properties); | |||
$this->assertEquals( | |||
new \OC\Connector\Sabre\TagList(array('tag1', 'tag2', 'tagkeep')), | |||
$result[200][self::TAGS_PROPERTYNAME] | |||
); | |||
$this->assertFalse(isset($result[200][self::FAVORITE_PROPERTYNAME])); | |||
} | |||
public function testUpdateFav() { | |||
// this test will replace the existing tags "tagremove" with "tag1" and "tag2" | |||
// and keep "tagkeep" | |||
$node = $this->getMockBuilder('\OC_Connector_Sabre_Node') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$node->expects($this->any()) | |||
->method('getId') | |||
->will($this->returnValue(123)); | |||
// set favorite tag | |||
$this->tagger->expects($this->once()) | |||
->method('tagAs') | |||
->with(123, self::TAG_FAVORITE); | |||
// properties to set | |||
$properties = array( | |||
self::FAVORITE_PROPERTYNAME => true | |||
); | |||
$result = array(); | |||
$this->plugin->updateProperties( | |||
$properties, | |||
$result, | |||
$node | |||
); | |||
// all requested properties removed, as they were processed already | |||
$this->assertEmpty($properties); | |||
$this->assertTrue($result[200][self::FAVORITE_PROPERTYNAME]); | |||
$this->assertFalse(isset($result[200][self::TAGS_PROPERTYNAME])); | |||
// unfavorite now | |||
// set favorite tag | |||
$this->tagger->expects($this->once()) | |||
->method('unTag') | |||
->with(123, self::TAG_FAVORITE); | |||
$properties = array( | |||
self::FAVORITE_PROPERTYNAME => false | |||
); | |||
$result = array(); | |||
$this->plugin->updateProperties( | |||
$properties, | |||
$result, | |||
$node | |||
); | |||
$this->assertFalse($result[200][self::FAVORITE_PROPERTYNAME]); | |||
$this->assertFalse(isset($result[200][self::TAGS_PROPERTYNAME])); | |||
} | |||
} |