From a24e7f655885b5047e73036acb2f1706803a2b65 Mon Sep 17 00:00:00 2001
From: Roeland Jago Douma <rullzer@owncloud.com>
Date: Fri, 29 Jan 2016 15:26:04 +0100
Subject: [PATCH] Add path filter to OCS Share API ?shared_with_me=true

This allows all clients to quickly get the share info for a given path.
Instead of returning everything and filtering it then manually on the
client side.
---
 apps/files_sharing/api/share20ocs.php         | 18 +++--
 lib/private/share20/defaultshareprovider.php  | 23 +++---
 lib/private/share20/manager.php               | 13 +---
 lib/public/share/imanager.php                 |  4 +-
 lib/public/share/ishareprovider.php           |  4 +-
 .../lib/share20/defaultshareprovidertest.php  | 78 ++++++++++++++++++-
 6 files changed, 109 insertions(+), 31 deletions(-)

diff --git a/apps/files_sharing/api/share20ocs.php b/apps/files_sharing/api/share20ocs.php
index 2dadc0888ec..8fe8991f9c9 100644
--- a/apps/files_sharing/api/share20ocs.php
+++ b/apps/files_sharing/api/share20ocs.php
@@ -329,9 +329,13 @@ class Share20OCS {
 		return new \OC_OCS_Result($share);
 	}
 
-	private function getSharedWithMe() {
-		$userShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, -1, 0);
-		$groupShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, -1, 0);
+	/**
+	 * @param \OCP\Files\File|\OCP\Files\Folder $node
+	 * @return \OC_OCS_Result
+	 */
+	private function getSharedWithMe($node = null) {
+		$userShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_USER, $node, -1, 0);
+		$groupShares = $this->shareManager->getSharedWith($this->currentUser, \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
 
 		$shares = array_merge($userShares, $groupShares);
 
@@ -390,10 +394,6 @@ class Share20OCS {
 		$subfiles = $this->request->getParam('subfiles');
 		$path = $this->request->getParam('path', null);
 
-		if ($sharedWithMe === 'true') {
-			return $this->getSharedWithMe();
-		}
-
 		if ($path !== null) {
 			$userFolder = $this->rootFolder->getUserFolder($this->currentUser->getUID());
 			try {
@@ -403,6 +403,10 @@ class Share20OCS {
 			}
 		}
 
+		if ($sharedWithMe === 'true') {
+			return $this->getSharedWithMe($path);
+		}
+
 		if ($subfiles === 'true') {
 			return $this->getSharesInDir($path);
 		}
diff --git a/lib/private/share20/defaultshareprovider.php b/lib/private/share20/defaultshareprovider.php
index 35b3f71f3de..0fa1552a1e7 100644
--- a/lib/private/share20/defaultshareprovider.php
+++ b/lib/private/share20/defaultshareprovider.php
@@ -518,16 +518,9 @@ class DefaultShareProvider implements IShareProvider {
 	}
 
 	/**
-	 * Get shared with the given user
-	 *
-	 * @param IUser $user get shares where this user is the recipient
-	 * @param int $shareType \OCP\Share::SHARE_TYPE_USER or \OCP\Share::SHARE_TYPE_GROUP are supported
-	 * @param int $limit The maximum number of shares, -1 for all
-	 * @param int $offset
-	 * @return IShare[]
-	 * @throws BackendError
+	 * @inheritdoc
 	 */
-	public function getSharedWith(IUser $user, $shareType, $limit, $offset) {
+	public function getSharedWith(IUser $user, $shareType, $node, $limit, $offset) {
 		/** @var Share[] $shares */
 		$shares = [];
 
@@ -549,6 +542,11 @@ class DefaultShareProvider implements IShareProvider {
 			$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)));
 			$qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($user->getUID())));
 
+			// Filter by node if provided
+			if ($node !== null) {
+				$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
+			}
+
 			$cursor = $qb->execute();
 
 			while($data = $cursor->fetch()) {
@@ -581,9 +579,14 @@ class DefaultShareProvider implements IShareProvider {
 					$qb->setMaxResults($limit - count($shares));
 				}
 
+				// Filter by node if provided
+				if ($node !== null) {
+					$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
+				}
+
 				$groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);
 
-				$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)));
+				$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)));
 				$qb->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter(
 					$groups,
 					IQueryBuilder::PARAM_STR_ARRAY
diff --git a/lib/private/share20/manager.php b/lib/private/share20/manager.php
index d6245f4beac..ad5fed93904 100644
--- a/lib/private/share20/manager.php
+++ b/lib/private/share20/manager.php
@@ -21,6 +21,7 @@
 
 namespace OC\Share20;
 
+use OCP\Files\Node;
 use OCP\Share\IManager;
 use OCP\Share\IProviderFactory;
 use OC\Share20\Exception\BackendError;
@@ -722,18 +723,12 @@ class Manager implements IManager {
 	}
 
 	/**
-	 * Get shares shared with $user.
-	 *
-	 * @param IUser $user
-	 * @param int $shareType
-	 * @param int $limit The maximum number of shares returned, -1 for all
-	 * @param int $offset
-	 * @return \OCP\Share\IShare[]
+	 * @inheritdoc
 	 */
-	public function getSharedWith(IUser $user, $shareType, $limit = 50, $offset = 0) {
+	public function getSharedWith(IUser $user, $shareType, $node = null, $limit = 50, $offset = 0) {
 		$provider = $this->factory->getProviderForType($shareType);
 
-		return $provider->getSharedWith($user, $shareType, $limit, $offset);
+		return $provider->getSharedWith($user, $shareType, $node, $limit, $offset);
 	}
 
 	/**
diff --git a/lib/public/share/imanager.php b/lib/public/share/imanager.php
index 6531c14a857..b2d9953e9ef 100644
--- a/lib/public/share/imanager.php
+++ b/lib/public/share/imanager.php
@@ -88,15 +88,17 @@ interface IManager {
 
 	/**
 	 * Get shares shared with $user.
+	 * Filter by $node if provided
 	 *
 	 * @param IUser $user
 	 * @param int $shareType
+	 * @param File|Folder|null $node
 	 * @param int $limit The maximum number of shares returned, -1 for all
 	 * @param int $offset
 	 * @return IShare[]
 	 * @since 9.0.0
 	 */
-	public function getSharedWith(IUser $user, $shareType, $limit = 50, $offset = 0);
+	public function getSharedWith(IUser $user, $shareType, $node = null, $limit = 50, $offset = 0);
 
 	/**
 	 * Retrieve a share by the share id
diff --git a/lib/public/share/ishareprovider.php b/lib/public/share/ishareprovider.php
index 50964c88dd6..8507462cbed 100644
--- a/lib/public/share/ishareprovider.php
+++ b/lib/public/share/ishareprovider.php
@@ -23,6 +23,7 @@ namespace OCP\Share;
 
 use OC\Share20\Exception\ShareNotFound;
 use OC\Share20\Exception\BackendError;
+use OCP\Files\Node;
 use OCP\IUser;
 
 /**
@@ -116,12 +117,13 @@ interface IShareProvider {
 	 *
 	 * @param IUser $user get shares where this user is the recipient
 	 * @param int $shareType
+	 * @param Node|null $node
 	 * @param int $limit The max number of entries returned, -1 for all
 	 * @param int $offset
 	 * @return \OCP\Share\IShare[]
 	 * @since 9.0.0
 	 */
-	public function getSharedWith(IUser $user, $shareType, $limit, $offset);
+	public function getSharedWith(IUser $user, $shareType, $node, $limit, $offset);
 
 	/**
 	 * Get a share by token
diff --git a/tests/lib/share20/defaultshareprovidertest.php b/tests/lib/share20/defaultshareprovidertest.php
index 45f2bedcb63..28b57435e1d 100644
--- a/tests/lib/share20/defaultshareprovidertest.php
+++ b/tests/lib/share20/defaultshareprovidertest.php
@@ -824,7 +824,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
 		$this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
 		$this->rootFolder->method('getById')->with(42)->willReturn([$file]);
 
-		$share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_USER, 1 , 0);
+		$share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_USER, null, 1 , 0);
 		$this->assertCount(1, $share);
 
 		$share = $share[0];
@@ -894,7 +894,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
 		$this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
 		$this->rootFolder->method('getById')->with(42)->willReturn([$file]);
 
-		$share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_GROUP, 20 , 1);
+		$share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_GROUP, null, 20 , 1);
 		$this->assertCount(1, $share);
 
 		$share = $share[0];
@@ -979,7 +979,7 @@ class DefaultShareProviderTest extends \Test\TestCase {
 		$this->rootFolder->method('getUserFolder')->with('shareOwner')->will($this->returnSelf());
 		$this->rootFolder->method('getById')->with(42)->willReturn([$file]);
 
-		$share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_GROUP, -1, 0);
+		$share = $this->provider->getSharedWith($user, \OCP\Share::SHARE_TYPE_GROUP, null, -1, 0);
 		$this->assertCount(1, $share);
 
 		$share = $share[0];
@@ -992,6 +992,78 @@ class DefaultShareProviderTest extends \Test\TestCase {
 		$this->assertSame('userTarget', $share->getTarget());
 	}
 
+	public function testGetSharedWithUserWithNode() {
+		$this->addShareToDB(\OCP\Share::SHARE_TYPE_USER, 'user0', 'user1', 'user1',
+			'file', 42, 'myTarget', 31, null, null, null);
+		$id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_USER, 'user0', 'user1', 'user1',
+			'file', 43, 'myTarget', 31, null, null, null);
+
+		$user0 = $this->getMock('\OCP\IUser');
+		$user0->method('getUID')->willReturn('user0');
+		$user1 = $this->getMock('\OCP\IUser');
+		$user1->method('getUID')->willReturn('user1');
+
+		$this->userManager->method('get')->willReturnMap([
+			['user0', $user0],
+			['user1', $user1],
+		]);
+
+		$file = $this->getMock('\OCP\Files\File');
+		$file->method('getId')->willReturn(43);
+		$this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+		$this->rootFolder->method('getById')->with(43)->willReturn([$file]);
+
+		$share = $this->provider->getSharedWith($user0, \OCP\Share::SHARE_TYPE_USER, $file, -1, 0);
+		$this->assertCount(1, $share);
+
+		$share = $share[0];
+		$this->assertEquals($id, $share->getId());
+		$this->assertSame($user0, $share->getSharedWith());
+		$this->assertSame($user1, $share->getShareOwner());
+		$this->assertSame($user1, $share->getSharedBy());
+		$this->assertSame($file, $share->getNode());
+		$this->assertEquals(\OCP\Share::SHARE_TYPE_USER, $share->getShareType());
+	}
+
+	public function testGetSharedWithGroupWithNode() {
+		$this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user1', 'user1',
+			'file', 42, 'myTarget', 31, null, null, null);
+		$id = $this->addShareToDB(\OCP\Share::SHARE_TYPE_GROUP, 'group0', 'user1', 'user1',
+			'file', 43, 'myTarget', 31, null, null, null);
+
+		$user0 = $this->getMock('\OCP\IUser');
+		$user0->method('getUID')->willReturn('user0');
+		$user1 = $this->getMock('\OCP\IUser');
+		$user1->method('getUID')->willReturn('user1');
+
+		$this->userManager->method('get')->willReturnMap([
+			['user0', $user0],
+			['user1', $user1],
+		]);
+
+		$group0 = $this->getMock('\OCP\IGroup');
+		$group0->method('getGID')->willReturn('group0');
+
+		$this->groupManager->method('get')->with('group0')->willReturn($group0);
+		$this->groupManager->method('getUserGroups')->with($user0)->willReturn([$group0]);
+
+		$node = $this->getMock('\OCP\Files\Folder');
+		$node->method('getId')->willReturn(43);
+		$this->rootFolder->method('getUserFolder')->with('user1')->will($this->returnSelf());
+		$this->rootFolder->method('getById')->with(43)->willReturn([$node]);
+
+		$share = $this->provider->getSharedWith($user0, \OCP\Share::SHARE_TYPE_GROUP, $node, -1, 0);
+		$this->assertCount(1, $share);
+
+		$share = $share[0];
+		$this->assertEquals($id, $share->getId());
+		$this->assertSame($group0, $share->getSharedWith());
+		$this->assertSame($user1, $share->getShareOwner());
+		$this->assertSame($user1, $share->getSharedBy());
+		$this->assertSame($node, $share->getNode());
+		$this->assertEquals(\OCP\Share::SHARE_TYPE_GROUP, $share->getShareType());
+	}
+
 	public function testGetSharesBy() {
 		$qb = $this->dbConn->getQueryBuilder();
 		$qb->insert('share')
-- 
GitLab