summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/federatedfilesharing/lib/FederatedShareProvider.php13
-rw-r--r--lib/private/Encryption/File.php4
-rw-r--r--lib/private/Share20/DefaultShareProvider.php54
-rw-r--r--lib/private/Share20/Manager.php16
-rw-r--r--lib/private/Share20/ShareHelper.php118
-rw-r--r--lib/public/Share/IManager.php5
-rw-r--r--lib/public/Share/IShareHelper.php7
-rw-r--r--lib/public/Share/IShareProvider.php7
8 files changed, 170 insertions, 54 deletions
diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php
index 29aa594df54..9e8d9fd9e47 100644
--- a/apps/federatedfilesharing/lib/FederatedShareProvider.php
+++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php
@@ -983,18 +983,23 @@ class FederatedShareProvider implements IShareProvider {
}
$qb = $this->dbConnection->getQueryBuilder();
- $qb->select('share_with')
+ $qb->select('share_with', 'file_source', 'file_target')
->from('share')
->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)))
->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
->andWhere($qb->expr()->orX(
$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
- ))
- ->setMaxResults(1);
+ ));
$cursor = $qb->execute();
- $remote = $cursor->fetch() !== false;
+ $remote = [];
+ while ($row = $cursor->fetch()) {
+ $remote[$row['share_with']] = [
+ 'node_id' => $row['file_source'],
+ 'node_path' => $row['file_target'],
+ ];
+ }
$cursor->closeCursor();
return ['remote' => $remote];
diff --git a/lib/private/Encryption/File.php b/lib/private/Encryption/File.php
index 3b6a87ef516..a1fd8e300d4 100644
--- a/lib/private/Encryption/File.php
+++ b/lib/private/Encryption/File.php
@@ -95,14 +95,14 @@ class File implements \OCP\Encryption\IFile {
$this->cache[$parent] = $resultForParents;
}
$userIds = \array_merge($userIds, $resultForParents['users']);
- $public = $resultForParents['public'] || $resultForParents['remote'];
+ $public = $resultForParents['public'] || !empty($resultForParents['remote']);
// Find out who, if anyone, is sharing the file
if ($file !== null) {
$resultForFile = $this->shareManager->getAccessList($file, false);
$userIds = array_merge($userIds, $resultForFile['users']);
- $public = $resultForFile['public'] || $resultForFile['remote'] || $public;
+ $public = $resultForFile['public'] || !empty($resultForFile['remote']) || $public;
}
// check if it is a group mount
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index b8f46a1f4d6..49a756f2a10 100644
--- a/lib/private/Share20/DefaultShareProvider.php
+++ b/lib/private/Share20/DefaultShareProvider.php
@@ -1092,7 +1092,7 @@ class DefaultShareProvider implements IShareProvider {
$or->add($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)));
}
- $qb->select('share_type', 'share_with')
+ $qb->select('id', 'parent', 'share_type', 'share_with', 'file_source', 'file_target', 'permissions')
->from('share')
->where(
$or
@@ -1110,7 +1110,8 @@ class DefaultShareProvider implements IShareProvider {
$type = (int)$row['share_type'];
if ($type === \OCP\Share::SHARE_TYPE_USER) {
$uid = $row['share_with'];
- $users[$uid] = isset($users[$uid]) ? $users[$uid] + 1 : 1;
+ $users[$uid] = isset($users[$uid]) ? $users[$uid] : [];
+ $users[$uid][$row['id']] = $row;
} else if ($type === \OCP\Share::SHARE_TYPE_GROUP) {
$gid = $row['share_with'];
$group = $this->groupManager->get($gid);
@@ -1121,23 +1122,60 @@ class DefaultShareProvider implements IShareProvider {
$userList = $group->getUsers();
foreach ($userList as $user) {
- $users[$user->getUID()] = isset($users[$user->getUID()]) ? $users[$user->getUID()] + 1 : 1;
+ $uid = $user->getUID();
+ $users[$uid] = isset($users[$uid]) ? $users[$uid] : [];
+ $users[$uid][$row['id']] = $row;
}
} else if ($type === \OCP\Share::SHARE_TYPE_LINK) {
$link = true;
} else if ($type === self::SHARE_TYPE_USERGROUP) {
if ($currentAccess === true) {
$uid = $row['share_with'];
- $users[$uid] = isset($users[$uid]) ? $users[$uid] - 1 : -1;
+ $users[$uid] = isset($users[$uid]) ? $users[$uid] : [];
+ $users[$uid][$row['id']] = $row;
}
}
}
$cursor->closeCursor();
- $users = array_filter($users, function($count) {
- return $count > 0;
- });
+ $users = array_map([$this, 'filterSharesOfUser'], $users);
- return ['users' => array_keys($users), 'public' => $link];
+ return ['users' => $users, 'public' => $link];
+ }
+
+ /**
+ * For each user the path with the fewest slashes is returned
+ * @param array $shares
+ * @return array
+ */
+ protected function filterSharesOfUser(array $shares) {
+ // Group shares when the user has a share exception
+ foreach ($shares as $id => $share) {
+ $type = (int) $share['share_type'];
+ $permissions = (int) $share['permissions'];
+
+ if ($type === self::SHARE_TYPE_USERGROUP) {
+ unset($shares[$share['parent']]);
+
+ if ($permissions === 0) {
+ unset($shares[$id]);
+ }
+ }
+ }
+
+ $best = [];
+ $bestDepth = 0;
+ foreach ($shares as $id => $share) {
+ $depth = substr_count($share['file_target'], '/');
+ if (empty($best) || $depth < $bestDepth) {
+ $bestDepth = $depth;
+ $best = [
+ 'node_id' => $share['file_source'],
+ 'node_path' => $share['file_target'],
+ ];
+ }
+ }
+
+ return $best;
}
}
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index f1ce66f008c..91fcb6af8fb 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -1191,9 +1191,10 @@ class Manager implements IManager {
*
* Then the access list will to '/folder1/folder2/fileA' is:
* [
- * users => ['user1', 'user2', 'user4'],
+ * users => ['user1' => ['node_id' => 42, 'node_path' => '/path'], 'user2' => [...]],
+ * remote => ['user1' => ['node_id' => 42, 'node_path' => '/path'], 'user2' => [...]],
* public => bool
- * remote => bool
+ * mail => bool
* ]
*
* This is required for encryption/activity
@@ -1206,7 +1207,7 @@ class Manager implements IManager {
public function getAccessList(\OCP\Files\Node $path, $recursive = true, $currentAccess = false) {
$owner = $path->getOwner()->getUID();
- $al = ['users' => [], 'public' => false, 'remote' => false];
+ $al = ['users' => [], 'remote' => [], 'public' => false];
if (!$this->userManager->userExists($owner)) {
return $al;
}
@@ -1222,7 +1223,12 @@ class Manager implements IManager {
/** @var Node[] $nodes */
$nodes = [];
- $al['users'][] = $owner;
+ $ownerPath = $path->getPath();
+ list(,,,$ownerPath) = explode('/', $ownerPath, 4);
+ $al['users'][$owner] = [
+ 'node_id' => $path->getId(),
+ 'node_path' => '/' . $ownerPath,
+ ];
// Collect all the shares
while ($path->getPath() !== $userFolder->getPath()) {
@@ -1249,8 +1255,6 @@ class Manager implements IManager {
}
}
- $al['users'] = array_unique($al['users']);
-
return $al;
}
diff --git a/lib/private/Share20/ShareHelper.php b/lib/private/Share20/ShareHelper.php
index a7d46457cd8..93b32cef3c3 100644
--- a/lib/private/Share20/ShareHelper.php
+++ b/lib/private/Share20/ShareHelper.php
@@ -22,43 +22,113 @@
*/
namespace OC\Share20;
-use OCP\Files\IRootFolder;
use OCP\Files\Node;
-use OCP\Files\NotFoundException;
+use OCP\Share\IManager;
+use OCP\Share\IShareHelper;
-class ShareHelper {
- /** @var IRootFolder */
- private $rootFolder;
+class ShareHelper implements IShareHelper {
- public function __construct(IRootFolder $rootFolder) {
- $this->rootFolder = $rootFolder;
+ /** @var IManager */
+ private $shareManager;
+
+ public function __construct(IManager $shareManager) {
+ $this->shareManager = $shareManager;
}
/**
- * If a user has access to a file
- *
* @param Node $node
- * @param array $users Array of userIds
- * @return array Mapping $uid to an array of nodes
+ * @return array [ users => [Mapping $uid => $path], remotes => [Mapping $cloudId => $path]]
*/
- public function getPathsForAccessList(Node $node, $users) {
- $result = [];
-
- foreach ($users as $user) {
- try {
- $userFolder = $this->rootFolder->getUserFolder($user);
- } catch (NotFoundException $e) {
- continue;
+ public function getPathsForAccessList(Node $node) {
+ $result = [
+ 'users' => [],
+ 'remotes' => [],
+ ];
+
+ $accessList = $this->shareManager->getAccessList($node, true, true);
+ if (!empty($accessList['users'])) {
+ $result['users'] = $this->getPathsForUsers($node, $accessList['users']);
+ }
+ if (!empty($accessList['remote'])) {
+ $result['remotes'] = $this->getPathsForRemotes($node, $accessList['remote']);
+ }
+
+ return $result;
+ }
+
+ protected function getPathsForUsers(Node $node, array $users) {
+ $byId = $results = [];
+ foreach ($users as $uid => $info) {
+ if (!isset($byId[$info['node_id']])) {
+ $byId[$info['node_id']] = [];
}
+ $byId[$info['node_id']][$uid] = $info['node_path'];
+ }
- $nodes = $userFolder->getById($node->getId());
- if ($nodes === []) {
- continue;
+ if (isset($byId[$node->getId()])) {
+ foreach ($byId[$node->getId()] as $uid => $path) {
+ $results[$uid] = $path;
}
+ unset($byId[$node->getId()]);
+ }
- $result[$user] = $nodes;
+ if (empty($byId)) {
+ return $results;
}
- return $result;
+ $item = $node;
+ $appendix = '/' . $node->getName();
+ while (!empty($byId)) {
+ $item = $item->getParent();
+
+ if (!empty($byId[$item->getId()])) {
+ foreach ($byId[$item->getId()] as $uid => $path) {
+ $results[$uid] = $path . $appendix;
+ }
+ unset($byId[$item->getId()]);
+ }
+
+ $appendix = '/' . $item->getName() . $appendix;
+ }
+
+ return $results;
+ }
+
+ protected function getPathsForRemotes(Node $node, array $remotes) {
+ $byId = $results = [];
+ foreach ($remotes as $cloudId => $info) {
+ if (!isset($byId[$info['node_id']])) {
+ $byId[$info['node_id']] = [];
+ }
+ $byId[$info['node_id']][$cloudId] = $info['node_path'];
+ }
+
+ if (isset($byId[$node->getId()])) {
+ foreach ($byId[$node->getId()] as $cloudId => $_) {
+ $results[$cloudId] = '/' . $node->getName();
+ }
+ unset($byId[$node->getId()]);
+ }
+
+ if (empty($byId)) {
+ return $results;
+ }
+
+ $item = $node;
+ $path = '/' . $node->getName();
+ while (!empty($byId)) {
+ $item = $item->getParent();
+
+ if (!empty($byId[$item->getId()])) {
+ foreach ($byId[$item->getId()] as $uid => $_) {
+ $results[$uid] = $path;
+ }
+ unset($byId[$item->getId()]);
+ }
+
+ $path = '/' . $item->getName() . $path;
+ }
+
+ return $results;
}
}
diff --git a/lib/public/Share/IManager.php b/lib/public/Share/IManager.php
index 26c3f2b42e6..1cbb27cb618 100644
--- a/lib/public/Share/IManager.php
+++ b/lib/public/Share/IManager.php
@@ -207,9 +207,10 @@ interface IManager {
*
* Then the access list will to '/folder1/folder2/fileA' is:
* [
- * users => ['user1', 'user2', 'user4'],
+ * users => ['user1' => ['node_id' => 42, 'node_path' => '/path'], 'user2' => [...]],
+ * remote => ['user1' => ['node_id' => 42, 'node_path' => '/path'], 'user2' => [...]],
* public => bool
- * remote => bool
+ * mail => bool
* ]
*
* This is required for encryption/activity
diff --git a/lib/public/Share/IShareHelper.php b/lib/public/Share/IShareHelper.php
index 5e99f86832d..01202cf477b 100644
--- a/lib/public/Share/IShareHelper.php
+++ b/lib/public/Share/IShareHelper.php
@@ -33,12 +33,9 @@ use OCP\Files\Node;
interface IShareHelper {
/**
- * If a user has access to a file
- *
* @param Node $node
- * @param array $users Array of userIds
- * @return array Mapping $uid to an array of nodes
+ * @return array [ users => [Mapping $uid => $path], remotes => [Mapping $cloudId => $path]]
* @since 12
*/
- public function getPathsForAccessList(Node $node, $users);
+ public function getPathsForAccessList(Node $node);
}
diff --git a/lib/public/Share/IShareProvider.php b/lib/public/Share/IShareProvider.php
index 2533e81abf2..fba432f31e7 100644
--- a/lib/public/Share/IShareProvider.php
+++ b/lib/public/Share/IShareProvider.php
@@ -196,14 +196,15 @@ interface IShareProvider {
* Return will look like:
*
* [
- * users => ['user1', 'user2', 'user4'],
+ * users => ['user1' => ['node_id' => 42, 'node_path' => '/path'], 'user2' => [...]],
+ * remote => ['user1' => ['node_id' => 42, 'node_path' => '/path'], 'user2' => [...]],
+ * mail => bool
* public => bool
- * remote => bool
* ]
*
* @param Node[] $nodes The list of nodes to get access for
* @param bool $currentAccess If current access is required (like for removed shares that might get revived later)
- * @return string[]
+ * @return array
* @since 12
*/
public function getAccessList($nodes, $currentAccess);