summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorThomas Müller <thomas.mueller@tmit.eu>2016-03-21 11:15:00 +0100
committerThomas Müller <thomas.mueller@tmit.eu>2016-03-21 11:15:00 +0100
commit8852fdaee3ee9b6bb52cbafcf358199321eb2307 (patch)
tree57816c31c2b480d42f04b05a2f49ff0dc391585d /apps
parente983bd7db074878d2418bdfcc22daf4689d9ec54 (diff)
parent6e6e002280587dea3b8ba5ae55f0514295f29108 (diff)
downloadnextcloud-server-8852fdaee3ee9b6bb52cbafcf358199321eb2307.tar.gz
nextcloud-server-8852fdaee3ee9b6bb52cbafcf358199321eb2307.zip
Merge pull request #22789 from owncloud/dav-sharesproperty
Add webdav property for share info in PROPFIND response
Diffstat (limited to 'apps')
-rw-r--r--apps/dav/lib/connector/sabre/serverfactory.php6
-rw-r--r--apps/dav/lib/connector/sabre/sharesplugin.php176
-rw-r--r--apps/dav/lib/connector/sabre/sharetypelist.php87
-rw-r--r--apps/dav/tests/unit/connector/sabre/sharesplugin.php257
-rw-r--r--apps/files/appinfo/application.php4
-rw-r--r--apps/files/controller/apicontroller.php54
-rw-r--r--apps/files/service/tagservice.php13
-rw-r--r--apps/files/tests/controller/apicontrollertest.php56
-rw-r--r--apps/files_sharing/js/share.js57
-rw-r--r--apps/files_sharing/js/sharedfilelist.js10
-rw-r--r--apps/files_sharing/tests/js/shareSpec.js33
11 files changed, 693 insertions, 60 deletions
diff --git a/apps/dav/lib/connector/sabre/serverfactory.php b/apps/dav/lib/connector/sabre/serverfactory.php
index 6ccec0bc0e8..080f889ae71 100644
--- a/apps/dav/lib/connector/sabre/serverfactory.php
+++ b/apps/dav/lib/connector/sabre/serverfactory.php
@@ -137,6 +137,12 @@ class ServerFactory {
if($this->userSession->isLoggedIn()) {
$server->addPlugin(new \OCA\DAV\Connector\Sabre\TagsPlugin($objectTree, $this->tagManager));
+ $server->addPlugin(new \OCA\DAV\Connector\Sabre\SharesPlugin(
+ $objectTree,
+ $this->userSession,
+ $userFolder,
+ \OC::$server->getShareManager()
+ ));
$server->addPlugin(new \OCA\DAV\Connector\Sabre\CommentPropertiesPlugin(\OC::$server->getCommentsManager(), $this->userSession));
$server->addPlugin(new \OCA\DAV\Connector\Sabre\FilesReportPlugin(
$objectTree,
diff --git a/apps/dav/lib/connector/sabre/sharesplugin.php b/apps/dav/lib/connector/sabre/sharesplugin.php
new file mode 100644
index 00000000000..f75c1378718
--- /dev/null
+++ b/apps/dav/lib/connector/sabre/sharesplugin.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, 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 <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\Connector\Sabre;
+
+use \Sabre\DAV\PropFind;
+use \Sabre\DAV\PropPatch;
+use OCP\IUserSession;
+use OCP\Share\IShare;
+use OCA\DAV\Connector\Sabre\ShareTypeList;
+
+/**
+ * Sabre Plugin to provide share-related properties
+ */
+class SharesPlugin extends \Sabre\DAV\ServerPlugin {
+
+ const NS_OWNCLOUD = 'http://owncloud.org/ns';
+ const SHARETYPES_PROPERTYNAME = '{http://owncloud.org/ns}share-types';
+
+ /**
+ * Reference to main server object
+ *
+ * @var \Sabre\DAV\Server
+ */
+ private $server;
+
+ /**
+ * @var \OCP\Share\IManager
+ */
+ private $shareManager;
+
+ /**
+ * @var \Sabre\DAV\Tree
+ */
+ private $tree;
+
+ /**
+ * @var string
+ */
+ private $userId;
+
+ /**
+ * @var \OCP\Files\Folder
+ */
+ private $userFolder;
+
+ /**
+ * @var IShare[]
+ */
+ private $cachedShareTypes;
+
+ /**
+ * @param \Sabre\DAV\Tree $tree tree
+ * @param IUserSession $userSession user session
+ * @param \OCP\Files\Folder $userFolder user home folder
+ * @param \OCP\Share\IManager $shareManager share manager
+ */
+ public function __construct(
+ \Sabre\DAV\Tree $tree,
+ IUserSession $userSession,
+ \OCP\Files\Folder $userFolder,
+ \OCP\Share\IManager $shareManager
+ ) {
+ $this->tree = $tree;
+ $this->shareManager = $shareManager;
+ $this->userFolder = $userFolder;
+ $this->userId = $userSession->getUser()->getUID();
+ $this->cachedShareTypes = [];
+ }
+
+ /**
+ * 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
+ */
+ public function initialize(\Sabre\DAV\Server $server) {
+ $server->xml->namespacesMap[self::NS_OWNCLOUD] = 'oc';
+ $server->xml->elementMap[self::SHARETYPES_PROPERTYNAME] = 'OCA\\DAV\\Connector\\Sabre\\ShareTypeList';
+ $server->protectedProperties[] = self::SHARETYPES_PROPERTYNAME;
+
+ $this->server = $server;
+ $this->server->on('propFind', array($this, 'handleGetProperties'));
+ }
+
+ /**
+ * Return a list of share types for outgoing shares
+ *
+ * @param \OCP\Files\Node $node file node
+ *
+ * @return int[] array of share types
+ */
+ private function getShareTypes(\OCP\Files\Node $node) {
+ $shareTypes = [];
+ $requestedShareTypes = [
+ \OCP\Share::SHARE_TYPE_USER,
+ \OCP\Share::SHARE_TYPE_GROUP,
+ \OCP\Share::SHARE_TYPE_LINK
+ ];
+ foreach ($requestedShareTypes as $requestedShareType) {
+ // one of each type is enough to find out about the types
+ $shares = $this->shareManager->getSharesBy(
+ $this->userId,
+ $requestedShareType,
+ $node,
+ false,
+ 1
+ );
+ if (!empty($shares)) {
+ $shareTypes[] = $requestedShareType;
+ }
+ }
+ return $shareTypes;
+ }
+
+ /**
+ * Adds shares to propfind response
+ *
+ * @param PropFind $propFind propfind object
+ * @param \Sabre\DAV\INode $sabreNode sabre node
+ */
+ public function handleGetProperties(
+ PropFind $propFind,
+ \Sabre\DAV\INode $sabreNode
+ ) {
+ if (!($sabreNode instanceof \OCA\DAV\Connector\Sabre\Node)) {
+ return;
+ }
+
+ // need prefetch ?
+ if ($sabreNode instanceof \OCA\DAV\Connector\Sabre\Directory
+ && $propFind->getDepth() !== 0
+ && !is_null($propFind->getStatus(self::SHARETYPES_PROPERTYNAME))
+ ) {
+ $folderNode = $this->userFolder->get($propFind->getPath());
+ $children = $folderNode->getDirectoryListing();
+
+ $this->cachedShareTypes[$folderNode->getId()] = $this->getShareTypes($folderNode);
+ foreach ($children as $childNode) {
+ $this->cachedShareTypes[$childNode->getId()] = $this->getShareTypes($childNode);
+ }
+ }
+
+ $propFind->handle(self::SHARETYPES_PROPERTYNAME, function() use ($sabreNode) {
+ if (isset($this->cachedShareTypes[$sabreNode->getId()])) {
+ $shareTypes = $this->cachedShareTypes[$sabreNode->getId()];
+ } else {
+ $node = $this->userFolder->get($sabreNode->getPath());
+ $shareTypes = $this->getShareTypes($node);
+ }
+
+ return new ShareTypeList($shareTypes);
+ });
+ }
+}
diff --git a/apps/dav/lib/connector/sabre/sharetypelist.php b/apps/dav/lib/connector/sabre/sharetypelist.php
new file mode 100644
index 00000000000..763586412ad
--- /dev/null
+++ b/apps/dav/lib/connector/sabre/sharetypelist.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCA\DAV\Connector\Sabre;
+
+use Sabre\Xml\Element;
+use Sabre\Xml\Reader;
+use Sabre\Xml\Writer;
+
+/**
+ * ShareTypeList property
+ *
+ * This property contains multiple "share-type" elements, each containing a share type.
+ */
+class ShareTypeList implements Element {
+ const NS_OWNCLOUD = 'http://owncloud.org/ns';
+
+ /**
+ * Share types
+ *
+ * @var int[]
+ */
+ private $shareTypes;
+
+ /**
+ * @param int[] $shareTypes
+ */
+ public function __construct($shareTypes) {
+ $this->shareTypes = $shareTypes;
+ }
+
+ /**
+ * Returns the share types
+ *
+ * @return int[]
+ */
+ public function getShareTypes() {
+ return $this->shareTypes;
+ }
+
+ /**
+ * The deserialize method is called during xml parsing.
+ *
+ * @param Reader $reader
+ * @return mixed
+ */
+ static function xmlDeserialize(Reader $reader) {
+ $shareTypes = [];
+
+ foreach ($reader->parseInnerTree() as $elem) {
+ if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}share-type') {
+ $shareTypes[] = (int)$elem['value'];
+ }
+ }
+ return new self($shareTypes);
+ }
+
+ /**
+ * The xmlSerialize metod is called during xml writing.
+ *
+ * @param Writer $writer
+ * @return void
+ */
+ function xmlSerialize(Writer $writer) {
+ foreach ($this->shareTypes as $shareType) {
+ $writer->writeElement('{' . self::NS_OWNCLOUD . '}share-type', $shareType);
+ }
+ }
+}
diff --git a/apps/dav/tests/unit/connector/sabre/sharesplugin.php b/apps/dav/tests/unit/connector/sabre/sharesplugin.php
new file mode 100644
index 00000000000..9a1c6eec507
--- /dev/null
+++ b/apps/dav/tests/unit/connector/sabre/sharesplugin.php
@@ -0,0 +1,257 @@
+<?php
+/**
+ * @author Vincent Petry <pvince81@owncloud.com>
+ *
+ * @copyright Copyright (c) 2016, 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 <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OCA\DAV\Tests\Unit\Connector\Sabre;
+
+class SharesPlugin extends \Test\TestCase {
+
+ const SHARETYPES_PROPERTYNAME = \OCA\DAV\Connector\Sabre\SharesPlugin::SHARETYPES_PROPERTYNAME;
+
+ /**
+ * @var \Sabre\DAV\Server
+ */
+ private $server;
+
+ /**
+ * @var \Sabre\DAV\Tree
+ */
+ private $tree;
+
+ /**
+ * @var \OCP\Share\IManager
+ */
+ private $shareManager;
+
+ /**
+ * @var \OCP\Files\Folder
+ */
+ private $userFolder;
+
+ /**
+ * @var \OCA\DAV\Connector\Sabre\SharesPlugin
+ */
+ private $plugin;
+
+ public function setUp() {
+ parent::setUp();
+ $this->server = new \Sabre\DAV\Server();
+ $this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->shareManager = $this->getMock('\OCP\Share\IManager');
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->once())
+ ->method('getUID')
+ ->will($this->returnValue('user1'));
+ $userSession = $this->getMock('\OCP\IUserSession');
+ $userSession->expects($this->once())
+ ->method('getUser')
+ ->will($this->returnValue($user));
+
+ $this->userFolder = $this->getMock('\OCP\Files\Folder');
+
+ $this->plugin = new \OCA\DAV\Connector\Sabre\SharesPlugin(
+ $this->tree,
+ $userSession,
+ $this->userFolder,
+ $this->shareManager
+ );
+ $this->plugin->initialize($this->server);
+ }
+
+ /**
+ * @dataProvider sharesGetPropertiesDataProvider
+ */
+ public function testGetProperties($shareTypes) {
+ $sabreNode = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Node')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $sabreNode->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(123));
+ $sabreNode->expects($this->once())
+ ->method('getPath')
+ ->will($this->returnValue('/subdir'));
+
+ // node API nodes
+ $node = $this->getMock('\OCP\Files\Folder');
+
+ $this->userFolder->expects($this->once())
+ ->method('get')
+ ->with('/subdir')
+ ->will($this->returnValue($node));
+
+ $this->shareManager->expects($this->any())
+ ->method('getSharesBy')
+ ->with(
+ $this->equalTo('user1'),
+ $this->anything(),
+ $this->anything(),
+ $this->equalTo(false),
+ $this->equalTo(1)
+ )
+ ->will($this->returnCallback(function($userId, $requestedShareType, $node, $flag, $limit) use ($shareTypes){
+ if (in_array($requestedShareType, $shareTypes)) {
+ return ['dummyshare'];
+ }
+ return [];
+ }));
+
+ $propFind = new \Sabre\DAV\PropFind(
+ '/dummyPath',
+ [self::SHARETYPES_PROPERTYNAME],
+ 0
+ );
+
+ $this->plugin->handleGetProperties(
+ $propFind,
+ $sabreNode
+ );
+
+ $result = $propFind->getResultForMultiStatus();
+
+ $this->assertEmpty($result[404]);
+ unset($result[404]);
+ $this->assertEquals($shareTypes, $result[200][self::SHARETYPES_PROPERTYNAME]->getShareTypes());
+ }
+
+ /**
+ * @dataProvider sharesGetPropertiesDataProvider
+ */
+ public function testPreloadThenGetProperties($shareTypes) {
+ $sabreNode1 = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $sabreNode1->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(111));
+ $sabreNode1->expects($this->never())
+ ->method('getPath');
+ $sabreNode2 = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $sabreNode2->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(222));
+ $sabreNode2->expects($this->never())
+ ->method('getPath');
+
+ $sabreNode = $this->getMockBuilder('\OCA\DAV\Connector\Sabre\Directory')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $sabreNode->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(123));
+ // never, because we use getDirectoryListing from the Node API instead
+ $sabreNode->expects($this->never())
+ ->method('getChildren');
+ $sabreNode->expects($this->any())
+ ->method('getPath')
+ ->will($this->returnValue('/subdir'));
+
+ // node API nodes
+ $node = $this->getMock('\OCP\Files\Folder');
+ $node->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(123));
+ $node1 = $this->getMock('\OCP\Files\File');
+ $node1->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(111));
+ $node2 = $this->getMock('\OCP\Files\File');
+ $node2->expects($this->any())
+ ->method('getId')
+ ->will($this->returnValue(222));
+ $node->expects($this->once())
+ ->method('getDirectoryListing')
+ ->will($this->returnValue([$node1, $node2]));
+
+ $this->userFolder->expects($this->once())
+ ->method('get')
+ ->with('/subdir')
+ ->will($this->returnValue($node));
+
+ $this->shareManager->expects($this->any())
+ ->method('getSharesBy')
+ ->with(
+ $this->equalTo('user1'),
+ $this->anything(),
+ $this->anything(),
+ $this->equalTo(false),
+ $this->equalTo(1)
+ )
+ ->will($this->returnCallback(function($userId, $requestedShareType, $node, $flag, $limit) use ($shareTypes){
+ if ($node->getId() === 111 && in_array($requestedShareType, $shareTypes)) {
+ return ['dummyshare'];
+ }
+
+ return [];
+ }));
+
+ // simulate sabre recursive PROPFIND traversal
+ $propFindRoot = new \Sabre\DAV\PropFind(
+ '/subdir',
+ [self::SHARETYPES_PROPERTYNAME],
+ 1
+ );
+ $propFind1 = new \Sabre\DAV\PropFind(
+ '/subdir/test.txt',
+ [self::SHARETYPES_PROPERTYNAME],
+ 0
+ );
+ $propFind2 = new \Sabre\DAV\PropFind(
+ '/subdir/test2.txt',
+ [self::SHARETYPES_PROPERTYNAME],
+ 0
+ );
+
+ $this->plugin->handleGetProperties(
+ $propFindRoot,
+ $sabreNode
+ );
+ $this->plugin->handleGetProperties(
+ $propFind1,
+ $sabreNode1
+ );
+ $this->plugin->handleGetProperties(
+ $propFind2,
+ $sabreNode2
+ );
+
+ $result = $propFind1->getResultForMultiStatus();
+
+ $this->assertEmpty($result[404]);
+ unset($result[404]);
+ $this->assertEquals($shareTypes, $result[200][self::SHARETYPES_PROPERTYNAME]->getShareTypes());
+ }
+
+ function sharesGetPropertiesDataProvider() {
+ return [
+ [[]],
+ [[\OCP\Share::SHARE_TYPE_USER]],
+ [[\OCP\Share::SHARE_TYPE_GROUP]],
+ [[\OCP\Share::SHARE_TYPE_LINK]],
+ [[\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP]],
+ [[\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK]],
+ [[\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_LINK]],
+ [[\OCP\Share::SHARE_TYPE_GROUP, \OCP\Share::SHARE_TYPE_LINK]],
+ ];
+ }
+}
diff --git a/apps/files/appinfo/application.php b/apps/files/appinfo/application.php
index bc6dc9fb9ed..593e0533c80 100644
--- a/apps/files/appinfo/application.php
+++ b/apps/files/appinfo/application.php
@@ -40,8 +40,10 @@ class Application extends App {
return new ApiController(
$c->query('AppName'),
$c->query('Request'),
+ $server->getUserSession(),
$c->query('TagService'),
- $server->getPreviewManager()
+ $server->getPreviewManager(),
+ $server->getShareManager()
);
});
diff --git a/apps/files/controller/apicontroller.php b/apps/files/controller/apicontroller.php
index c96d92a046b..43abf2ff458 100644
--- a/apps/files/controller/apicontroller.php
+++ b/apps/files/controller/apicontroller.php
@@ -34,6 +34,10 @@ use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\DataDisplayResponse;
use OCA\Files\Service\TagService;
use OCP\IPreview;
+use OCP\Share\IManager;
+use OCP\Files\FileInfo;
+use OCP\Files\Node;
+use OCP\IUserSession;
/**
* Class ApiController
@@ -43,8 +47,12 @@ use OCP\IPreview;
class ApiController extends Controller {
/** @var TagService */
private $tagService;
+ /** @var IManager **/
+ private $shareManager;
/** @var IPreview */
private $previewManager;
+ /** IUserSession */
+ private $userSession;
/**
* @param string $appName
@@ -54,11 +62,15 @@ class ApiController extends Controller {
*/
public function __construct($appName,
IRequest $request,
+ IUserSession $userSession,
TagService $tagService,
- IPreview $previewManager){
+ IPreview $previewManager,
+ IManager $shareManager) {
parent::__construct($appName, $request);
+ $this->userSession = $userSession;
$this->tagService = $tagService;
$this->previewManager = $previewManager;
+ $this->shareManager = $shareManager;
}
/**
@@ -132,8 +144,10 @@ class ApiController extends Controller {
*/
public function getFilesByTag($tagName) {
$files = array();
- $fileInfos = $this->tagService->getFilesByTag($tagName);
- foreach ($fileInfos as &$fileInfo) {
+ $nodes = $this->tagService->getFilesByTag($tagName);
+ foreach ($nodes as &$node) {
+ $shareTypes = $this->getShareTypes($node);
+ $fileInfo = $node->getFileInfo();
$file = \OCA\Files\Helper::formatFileInfo($fileInfo);
$parts = explode('/', dirname($fileInfo->getPath()), 4);
if(isset($parts[3])) {
@@ -142,9 +156,43 @@ class ApiController extends Controller {
$file['path'] = '/';
}
$file['tags'] = [$tagName];
+ if (!empty($shareTypes)) {
+ $file['shareTypes'] = $shareTypes;
+ }
$files[] = $file;
}
return new DataResponse(['files' => $files]);
}
+ /**
+ * Return a list of share types for outgoing shares
+ *
+ * @param Node $node file node
+ *
+ * @return int[] array of share types
+ */
+ private function getShareTypes(Node $node) {
+ $userId = $this->userSession->getUser()->getUID();
+ $shareTypes = [];
+ $requestedShareTypes = [
+ \OCP\Share::SHARE_TYPE_USER,
+ \OCP\Share::SHARE_TYPE_GROUP,
+ \OCP\Share::SHARE_TYPE_LINK
+ ];
+ foreach ($requestedShareTypes as $requestedShareType) {
+ // one of each type is enough to find out about the types
+ $shares = $this->shareManager->getSharesBy(
+ $userId,
+ $requestedShareType,
+ $node,
+ false,
+ 1
+ );
+ if (!empty($shares)) {
+ $shareTypes[] = $requestedShareType;
+ }
+ }
+ return $shareTypes;
+ }
+
}
diff --git a/apps/files/service/tagservice.php b/apps/files/service/tagservice.php
index e1425c46615..57cad43a539 100644
--- a/apps/files/service/tagservice.php
+++ b/apps/files/service/tagservice.php
@@ -25,6 +25,7 @@
namespace OCA\Files\Service;
use OC\Files\FileInfo;
+use OCP\Files\Node;
/**
* Service class to manage tags on files.
@@ -93,7 +94,7 @@ class TagService {
* Get all files for the given tag
*
* @param string $tagName tag name to filter by
- * @return FileInfo[] list of matching files
+ * @return Node[] list of matching files
* @throws \Exception if the tag does not exist
*/
public function getFilesByTag($tagName) {
@@ -103,15 +104,11 @@ class TagService {
return [];
}
- $fileInfos = [];
+ $allNodes = [];
foreach ($fileIds as $fileId) {
- $nodes = $this->homeFolder->getById((int) $fileId);
- foreach ($nodes as $node) {
- /** @var \OC\Files\Node\Node $node */
- $fileInfos[] = $node->getFileInfo();
- }
+ $allNodes = array_merge($allNodes, $this->homeFolder->getById((int) $fileId));
}
- return $fileInfos;
+ return $allNodes;
}
}
diff --git a/apps/files/tests/controller/apicontrollertest.php b/apps/files/tests/controller/apicontrollertest.php
index 6fb8340ead8..a9b248a36fe 100644
--- a/apps/files/tests/controller/apicontrollertest.php
+++ b/apps/files/tests/controller/apicontrollertest.php
@@ -51,14 +51,27 @@ class ApiControllerTest extends TestCase {
private $preview;
/** @var ApiController */
private $apiController;
+ /** @var \OCP\Share\IManager */
+ private $shareManager;
public function setUp() {
$this->request = $this->getMockBuilder('\OCP\IRequest')
->disableOriginalConstructor()
->getMock();
+ $user = $this->getMock('\OCP\IUser');
+ $user->expects($this->any())
+ ->method('getUID')
+ ->will($this->returnValue('user1'));
+ $userSession = $this->getMock('\OCP\IUserSession');
+ $userSession->expects($this->any())
+ ->method('getUser')
+ ->will($this->returnValue($user));
$this->tagService = $this->getMockBuilder('\OCA\Files\Service\TagService')
->disableOriginalConstructor()
->getMock();
+ $this->shareManager = $this->getMockBuilder('\OCP\Share\IManager')
+ ->disableOriginalConstructor()
+ ->getMock();
$this->preview = $this->getMockBuilder('\OCP\IPreview')
->disableOriginalConstructor()
->getMock();
@@ -66,8 +79,10 @@ class ApiControllerTest extends TestCase {
$this->apiController = new ApiController(
$this->appName,
$this->request,
+ $userSession,
$this->tagService,
- $this->preview
+ $this->preview,
+ $this->shareManager
);
}
@@ -101,10 +116,32 @@ class ApiControllerTest extends TestCase {
->disableOriginalConstructor()
->getMock()
);
+ $node = $this->getMockBuilder('\OC\Files\Node\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node->expects($this->once())
+ ->method('getFileInfo')
+ ->will($this->returnValue($fileInfo));
$this->tagService->expects($this->once())
->method('getFilesByTag')
->with($this->equalTo([$tagName]))
- ->will($this->returnValue([$fileInfo]));
+ ->will($this->returnValue([$node]));
+
+ $this->shareManager->expects($this->any())
+ ->method('getSharesBy')
+ ->with(
+ $this->equalTo('user1'),
+ $this->anything(),
+ $node,
+ $this->equalTo(false),
+ $this->equalTo(1)
+ )
+ ->will($this->returnCallback(function($userId, $shareType) {
+ if ($shareType === \OCP\Share::SHARE_TYPE_USER || $shareType === \OCP\Share::SHARE_TYPE_LINK) {
+ return ['dummy_share'];
+ }
+ return [];
+ }));
$expected = new DataResponse([
'files' => [
@@ -124,6 +161,7 @@ class ApiControllerTest extends TestCase {
'MyTagName'
]
],
+ 'shareTypes' => [\OCP\Share::SHARE_TYPE_USER, \OCP\Share::SHARE_TYPE_LINK]
],
],
]);
@@ -166,10 +204,22 @@ class ApiControllerTest extends TestCase {
->disableOriginalConstructor()
->getMock()
);
+ $node1 = $this->getMockBuilder('\OC\Files\Node\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node1->expects($this->once())
+ ->method('getFileInfo')
+ ->will($this->returnValue($fileInfo1));
+ $node2 = $this->getMockBuilder('\OC\Files\Node\File')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $node2->expects($this->once())
+ ->method('getFileInfo')
+ ->will($this->returnValue($fileInfo2));
$this->tagService->expects($this->once())
->method('getFilesByTag')
->with($this->equalTo([$tagName]))
- ->will($this->returnValue([$fileInfo1, $fileInfo2]));
+ ->will($this->returnValue([$node1, $node2]));
$expected = new DataResponse([
'files' => [
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index 2711b2392e9..5ec7824758f 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -60,6 +60,9 @@
if (fileData.recipientsDisplayName) {
tr.attr('data-share-recipients', fileData.recipientsDisplayName);
}
+ if (fileData.shareTypes) {
+ tr.attr('data-share-types', fileData.shareTypes.join(','));
+ }
return tr;
};
@@ -77,6 +80,7 @@
fileList._getWebdavProperties = function() {
var props = oldGetWebdavProperties.apply(this, arguments);
props.push('{' + NS_OC + '}owner-display-name');
+ props.push('{' + NS_OC + '}share-types');
return props;
};
@@ -88,40 +92,45 @@
if (permissionsProp && permissionsProp.indexOf('S') >= 0) {
data.shareOwner = props['{' + NS_OC + '}owner-display-name'];
}
+
+ var shareTypesProp = props['{' + NS_OC + '}share-types'];
+ if (shareTypesProp) {
+ data.shareTypes = _.chain(shareTypesProp).filter(function(xmlvalue) {
+ return (xmlvalue.namespaceURI === NS_OC && xmlvalue.nodeName.split(':')[1] === 'share-type');
+ }).map(function(xmlvalue) {
+ return parseInt(xmlvalue.textContent || xmlvalue.text, 10);
+ }).value();
+ }
+
return data;
});
// use delegate to catch the case with multiple file lists
fileList.$el.on('fileActionsReady', function(ev){
- var fileList = ev.fileList;
var $files = ev.$files;
- function updateIcons($files) {
- if (!$files) {
- // if none specified, update all
- $files = fileList.$fileList.find('tr');
+ _.each($files, function(file) {
+ var $tr = $(file);
+ var shareTypes = $tr.attr('data-share-types');
+ if (shareTypes) {
+ var hasLink = false;
+ var hasShares = false;
+ _.each(shareTypes.split(',') || [], function(shareType) {
+ shareType = parseInt(shareType, 10);
+ if (shareType === OC.Share.SHARE_TYPE_LINK) {
+ hasLink = true;
+ } else if (shareType === OC.Share.SHARE_TYPE_USER) {
+ hasShares = true;
+ } else if (shareType === OC.Share.SHARE_TYPE_GROUP) {
+ hasShares = true;
+ }
+ });
+ OCA.Sharing.Util._updateFileActionIcon($tr, hasShares, hasLink);
}
- _.each($files, function(file) {
- var $tr = $(file);
- var shareStatus = OC.Share.statuses[$tr.data('id')];
- OCA.Sharing.Util._updateFileActionIcon($tr, !!shareStatus, shareStatus && shareStatus.link);
- });
- }
-
- if (!OCA.Sharing.sharesLoaded){
- OC.Share.loadIcons('file', fileList, function() {
- // since we don't know which files are affected, just refresh them all
- updateIcons();
- });
- // assume that we got all shares, so switching directories
- // will not invalidate that list
- OCA.Sharing.sharesLoaded = true;
- }
- else{
- updateIcons($files);
- }
+ });
});
+
fileList.$el.on('changeDirectory', function() {
OCA.Sharing.sharesLoaded = false;
});
diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js
index a799d4a94c2..da0f957ed99 100644
--- a/apps/files_sharing/js/sharedfilelist.js
+++ b/apps/files_sharing/js/sharedfilelist.js
@@ -286,6 +286,8 @@
// using a hash to make them unique,
// this is only a list to be displayed
data.recipients = {};
+ // share types
+ data.shareTypes = {};
// counter is cheaper than calling _.keys().length
data.recipientsCount = 0;
data.mtime = file.share.stime;
@@ -308,6 +310,8 @@
data.recipientsCount++;
}
+ data.shareTypes[file.share.type] = true;
+
delete file.share;
return memo;
}, {})
@@ -324,6 +328,12 @@
data.recipientsCount
);
delete data.recipientsCount;
+ if (self._sharedWithUser) {
+ // only for outgoing shres
+ delete data.shareTypes;
+ } else {
+ data.shareTypes = _.keys(data.shareTypes);
+ }
})
// Finish the chain by getting the result
.value();
diff --git a/apps/files_sharing/tests/js/shareSpec.js b/apps/files_sharing/tests/js/shareSpec.js
index 7607ada50ba..c488bd94fab 100644
--- a/apps/files_sharing/tests/js/shareSpec.js
+++ b/apps/files_sharing/tests/js/shareSpec.js
@@ -53,35 +53,21 @@ describe('OCA.Sharing.Util tests', function() {
permissions: OC.PERMISSION_ALL,
etag: 'abc',
shareOwner: 'User One',
- isShareMountPoint: false
+ isShareMountPoint: false,
+ shareTypes: [OC.Share.SHARE_TYPE_USER]
}];
-
- OCA.Sharing.sharesLoaded = true;
- OC.Share.statuses = {
- 1: {link: false, path: '/subdir'}
- };
});
afterEach(function() {
delete OCA.Sharing.sharesLoaded;
delete OC.Share.droppedDown;
fileList.destroy();
fileList = null;
- OC.Share.statuses = {};
- OC.Share.currentShares = {};
});
describe('Sharing data in table row', function() {
// TODO: test data-permissions, data-share-owner, etc
});
describe('Share action icon', function() {
- beforeEach(function() {
- OC.Share.statuses = {1: {link: false, path: '/subdir'}};
- OCA.Sharing.sharesLoaded = true;
- });
- afterEach(function() {
- OC.Share.statuses = {};
- OCA.Sharing.sharesLoaded = false;
- });
it('do not shows share text when not shared', function() {
var $action, $tr;
OC.Share.statuses = {};
@@ -93,7 +79,8 @@ describe('OCA.Sharing.Util tests', function() {
mimetype: 'httpd/unix-directory',
size: 12,
permissions: OC.PERMISSION_ALL,
- etag: 'abc'
+ etag: 'abc',
+ shareTypes: []
}]);
$tr = fileList.$el.find('tbody tr:first');
$action = $tr.find('.action-share');
@@ -111,7 +98,8 @@ describe('OCA.Sharing.Util tests', function() {
mimetype: 'text/plain',
size: 12,
permissions: OC.PERMISSION_ALL,
- etag: 'abc'
+ etag: 'abc',
+ shareTypes: [OC.Share.SHARE_TYPE_USER]
}]);
$tr = fileList.$el.find('tbody tr:first');
$action = $tr.find('.action-share');
@@ -131,7 +119,8 @@ describe('OCA.Sharing.Util tests', function() {
mimetype: 'text/plain',
size: 12,
permissions: OC.PERMISSION_ALL,
- etag: 'abc'
+ etag: 'abc',
+ shareTypes: [OC.Share.SHARE_TYPE_LINK]
}]);
$tr = fileList.$el.find('tbody tr:first');
$action = $tr.find('.action-share');
@@ -151,7 +140,8 @@ describe('OCA.Sharing.Util tests', function() {
size: 12,
permissions: OC.PERMISSION_ALL,
shareOwner: 'User One',
- etag: 'abc'
+ etag: 'abc',
+ shareTypes: [OC.Share.SHARE_TYPE_USER]
}]);
$tr = fileList.$el.find('tbody tr:first');
$action = $tr.find('.action-share');
@@ -171,7 +161,8 @@ describe('OCA.Sharing.Util tests', function() {
size: 12,
permissions: OC.PERMISSION_ALL,
recipientsDisplayName: 'User One, User Two',
- etag: 'abc'
+ etag: 'abc',
+ shareTypes: [OC.Share.SHARE_TYPE_USER]
}]);
$tr = fileList.$el.find('tbody tr:first');
$action = $tr.find('.action-share');