diff options
author | Bjoern Schiessle <schiessle@owncloud.com> | 2014-07-31 11:55:59 +0200 |
---|---|---|
committer | Bjoern Schiessle <schiessle@owncloud.com> | 2014-09-22 17:25:15 +0200 |
commit | 89c3b650e6c47899ceea105713b389fe8af78bfa (patch) | |
tree | c5c653bcfe7de1f81dc1889636989aade9bc1eae /lib | |
parent | 0d37e16499fd0bda83d4c41dfba626b3d9a489f5 (diff) | |
download | nextcloud-server-89c3b650e6c47899ceea105713b389fe8af78bfa.tar.gz nextcloud-server-89c3b650e6c47899ceea105713b389fe8af78bfa.zip |
group shares and combine permissions
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/share/share.php | 486 |
1 files changed, 249 insertions, 237 deletions
diff --git a/lib/private/share/share.php b/lib/private/share/share.php index 8441e6a94c4..8b0e98b66fe 100644 --- a/lib/private/share/share.php +++ b/lib/private/share/share.php @@ -339,11 +339,13 @@ class Share extends \OC\Share\Constants { * @param int $format (optional) Format type must be defined by the backend * @param mixed $parameters * @param boolean $includeCollections + * @param string $shareWith (optional) define against which user should be checked, default: current user * @return mixed Return depends on format */ public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE, - $parameters = null, $includeCollections = false) { - return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format, + $parameters = null, $includeCollections = false, $shareWith = null) { + $shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith; + return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format, $parameters, 1, $includeCollections, true); } @@ -1297,7 +1299,7 @@ class Share extends \OC\Share\Constants { // Make sure the unique user target is returned if it exists, // unique targets should follow the group share in the database // If the limit is not 1, the filtering can be done later - $where .= ' ORDER BY `*PREFIX*share`.`id` DESC'; + $where .= ' ORDER BY `*PREFIX*share`.`id` ASC'; } // The limit must be at least 3, because filtering needs to be done if ($limit < 3) { @@ -1315,7 +1317,7 @@ class Share extends \OC\Share\Constants { $result = $query->execute($queryArgs); if (\OC_DB::isError($result)) { \OC_Log::write('OCP\Share', - \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, + \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=', \OC_Log::ERROR); } $items = array(); @@ -1416,7 +1418,13 @@ class Share extends \OC\Share\Constants { } $items[$row['id']] = $row; + + } + + if (isset($shareWith) && $shareWith === \OCP\User::getUser()) { + $items = self::groupItems($items, $itemType); } + if (!empty($items)) { $collectionItems = array(); foreach ($items as &$row) { @@ -1502,6 +1510,47 @@ class Share extends \OC\Share\Constants { } /** + * group items with link to the same source + * + * @param array $items + * @param string $itemType + * @return array of grouped items + */ + private static function groupItems($items, $itemType) { + + $fileSharing = ($itemType === 'file' || $itemType === 'folder') ? true : false; + + $result = array(); + + foreach ($items as $item) { + $grouped = false; + foreach ($result as $key => $r) { + // for file/folder shares we need to compare file_source, otherwise we compare item_source + // only group shares if they already point to the same target, otherwise the file where shared + // before grouping of shares was added. In this case we don't group them toi avoid confusions + if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) || + (!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) { + // add the first item to the list of grouped shares + if (!isset($result[$key]['grouped'])) { + $result[$key]['grouped'][] = $result[$key]; + } + $result[$key]['permissions'] = (int) $item['permissions'] | (int) $r['permissions']; + $result[$key]['grouped'][] = $item; + $grouped = true; + break; + } + } + + if (!$grouped) { + $result[] = $item; + } + + } + + return $result; + } + +/** * Put shared item into the database * @param string $itemType Item type * @param string $itemSource Item source @@ -1518,11 +1567,184 @@ class Share extends \OC\Share\Constants { */ private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) { + + $queriesToExecute = array(); + + $fileShare = false; + if ($itemType === 'file' || $itemType === 'folder') { + $fileShare = true; + } + + $result = self::checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate); + if(!empty($result)) { + $parent = $result['parent']; + $itemSource = $result['itemSource']; + $fileSource = $result['fileSource']; + $suggestedItemTarget = $result['suggestedItemTarget']; + $suggestedFileTarget = $result['suggestedFileTarget']; + $filePath = $result['filePath']; + $expirationDate = $result['expirationDate']; + } + + $isGroupShare = false; + if ($shareType == self::SHARE_TYPE_GROUP) { + $isGroupShare = true; + $users = \OC_Group::usersInGroup($shareWith['group']); + // remove current user from list + if (in_array(\OCP\User::getUser(), $users)) { + unset($users[array_search(\OCP\User::getUser(), $users)]); + } + $groupItemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'], + $uidOwner, $suggestedItemTarget); + $groupFileTarget = $filePath; + + // add group share to table and remember the id as parent + $queriesToExecute['groupShare'] = array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'itemTarget' => $groupItemTarget, + 'shareType' => $shareType, + 'shareWith' => $shareWith['group'], + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'shareTime' => time(), + 'fileSource' => $fileSource, + 'fileTarget' => $filePath, + 'token' => $token, + 'parent' => $parent, + 'expiration' => $expirationDate, + ); + + } else { + $users = array($shareWith); + $itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, + $suggestedItemTarget); + } + + $run = true; + $error = ''; + $preHookData = array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'shareType' => $shareType, + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'expiration' => $expirationDate, + 'token' => $token, + 'run' => &$run, + 'error' => &$error + ); + + $preHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget; + $preHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith; + + \OC_Hook::emit('OCP\Share', 'pre_shared', $preHookData); + + if ($run === false) { + throw new \Exception($error); + } + + foreach ($users as $user) { + $sourceExists = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true, $user); + + $shareType = ($isGroupShare) ? self::$shareTypeGroupUserUnique : $shareType; + + if ($sourceExists) { + $fileTarget = $sourceExists['file_target']; + $itemTarget = $sourceExists['item_target']; + + } elseif(!$sourceExists && !$isGroupShare) { + + $itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $user, + $uidOwner, $suggestedItemTarget, $parent); + if (isset($fileSource)) { + if ($parentFolder) { + if ($parentFolder === true) { + $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user, + $uidOwner, $suggestedFileTarget, $parent); + if ($fileTarget != $groupFileTarget) { + $parentFolders[$user]['folder'] = $fileTarget; + } + } else if (isset($parentFolder[$user])) { + $fileTarget = $parentFolder[$user]['folder'].$itemSource; + $parent = $parentFolder[$user]['id']; + } + } else { + $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, + $user, $uidOwner, $suggestedFileTarget, $parent); + } + } else { + $fileTarget = null; + } + + } else { + // move to the next user if it is neither a unique group share + // nor a single share without adding it to the share table + continue; + } + + $queriesToExecute[] = array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'itemTarget' => $itemTarget, + 'shareType' => $shareType, + 'shareWith' => $user, + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'shareTime' => time(), + 'fileSource' => $fileSource, + 'fileTarget' => $fileTarget, + 'token' => $token, + 'parent' => $parent, + 'expiration' => $expirationDate, + ); + + } + + if ($isGroupShare) { + self::insertShare($queriesToExecute['groupShare']); + // Save this id, any extra rows for this group share will need to reference it + $parent = \OC_DB::insertid('*PREFIX*share'); + unset($queriesToExecute['groupShare']); + } + + foreach ($queriesToExecute as $shareQuery) { + $shareQuery['parent'] = $parent; + self::insertShare($shareQuery); + } + + $postHookData = array( + 'itemType' => $itemType, + 'itemSource' => $itemSource, + 'parent' => $parent, + 'shareType' => $shareType, + 'uidOwner' => $uidOwner, + 'permissions' => $permissions, + 'fileSource' => $fileSource, + 'id' => $parent, + 'token' => $token, + 'expirationDate' => $expirationDate, + ); + + $postHookData['shareWith'] = ($isGroupShare) ? $shareWith['group'] : $shareWith; + $postHookData['itemTarget'] = ($isGroupShare) ? $groupItemTarget : $itemTarget; + $postHookData['fileTarget'] = ($isGroupShare) ? $groupFileTarget : $fileTarget; + + \OC_Hook::emit('OCP\Share', 'post_shared', $postHookData); + + + return true; + } + + private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) { $backend = self::getBackend($itemType); + $l = \OC::$server->getL10N('lib'); - // Check if this is a reshare - if ($checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true)) { + $result = array(); + $checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true); + if ($checkReshare) { // Check if attempting to share back to owner if ($checkReshare['uid_owner'] == $shareWith && $shareType == self::SHARE_TYPE_USER) { $message = 'Sharing %s failed, because the user %s is the original sharer'; @@ -1531,6 +1753,7 @@ class Share extends \OC\Share\Constants { \OC_Log::write('OCP\Share', sprintf($message, $itemSourceName, $shareWith), \OC_Log::ERROR); throw new \Exception($message_t); } + // Check if share permissions is granted if (self::isResharingAllowed() && (int)$checkReshare['permissions'] & \OCP\PERMISSION_SHARE) { if (~(int)$checkReshare['permissions'] & $permissions) { @@ -1541,13 +1764,13 @@ class Share extends \OC\Share\Constants { throw new \Exception($message_t); } else { // TODO Don't check if inside folder - $parent = $checkReshare['id']; - $itemSource = $checkReshare['item_source']; - $fileSource = $checkReshare['file_source']; - $suggestedItemTarget = $checkReshare['item_target']; - $suggestedFileTarget = $checkReshare['file_target']; - $filePath = $checkReshare['file_target']; - $expirationDate = min($expirationDate, $checkReshare['expiration']); + $result['parent'] = $checkReshare['id']; + $result['itemSource'] = $checkReshare['item_source']; + $result['fileSource'] = $checkReshare['file_source']; + $result['suggestedItemTarget'] = $checkReshare['item_target']; + $result['suggestedFileTarget'] = $checkReshare['file_target']; + $result['filePath'] = $checkReshare['file_target']; + $result['expirationDate'] = min($expirationDate, $checkReshare['expiration']); } } else { $message = 'Sharing %s failed, because resharing is not allowed'; @@ -1557,9 +1780,11 @@ class Share extends \OC\Share\Constants { throw new \Exception($message_t); } } else { - $parent = null; - $suggestedItemTarget = null; - $suggestedFileTarget = null; + $result['parent'] = null; + $result['suggestedItemTarget'] = null; + $result['suggestedFileTarget'] = null; + $result['itemSource'] = $itemSource; + $result['expirationDate'] = $expirationDate; if (!$backend->isValidSource($itemSource, $uidOwner)) { $message = 'Sharing %s failed, because the sharing backend for ' .'%s could not find its source'; @@ -1568,14 +1793,14 @@ class Share extends \OC\Share\Constants { throw new \Exception($message_t); } if ($backend instanceof \OCP\Share_Backend_File_Dependent) { - $filePath = $backend->getFilePath($itemSource, $uidOwner); + $result['filePath'] = $backend->getFilePath($itemSource, $uidOwner); if ($itemType == 'file' || $itemType == 'folder') { - $fileSource = $itemSource; + $result['fileSource'] = $itemSource; } else { - $meta = \OC\Files\Filesystem::getFileInfo($filePath); - $fileSource = $meta['fileid']; + $meta = \OC\Files\Filesystem::getFileInfo($result['filePath']); + $result['fileSource'] = $meta['fileid']; } - if ($fileSource == -1) { + if ($result['fileSource'] == -1) { $message = 'Sharing %s failed, because the file could not be found in the file cache'; $message_t = $l->t('Sharing %s failed, because the file could not be found in the file cache', array($itemSource)); @@ -1583,225 +1808,12 @@ class Share extends \OC\Share\Constants { throw new \Exception($message_t); } } else { - $filePath = null; - $fileSource = null; + $result['filePath'] = null; + $result['fileSource'] = null; } } - // Share with a group - if ($shareType == self::SHARE_TYPE_GROUP) { - $groupItemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'], - $uidOwner, $suggestedItemTarget); - $run = true; - $error = ''; - \OC_Hook::emit('OCP\Share', 'pre_shared', array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'itemTarget' => $groupItemTarget, - 'shareType' => $shareType, - 'shareWith' => $shareWith['group'], - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'fileSource' => $fileSource, - 'expiration' => $expirationDate, - 'token' => $token, - 'run' => &$run, - 'error' => &$error - )); - - if ($run === false) { - throw new \Exception($error); - } - - if (isset($fileSource)) { - if ($parentFolder) { - if ($parentFolder === true) { - $groupFileTarget = Helper::generateTarget('file', $filePath, $shareType, - $shareWith['group'], $uidOwner, $suggestedFileTarget); - // Set group default file target for future use - $parentFolders[0]['folder'] = $groupFileTarget; - } else { - // Get group default file target - $groupFileTarget = $parentFolder[0]['folder'].$itemSource; - $parent = $parentFolder[0]['id']; - } - } else { - $groupFileTarget = Helper::generateTarget('file', $filePath, $shareType, $shareWith['group'], - $uidOwner, $suggestedFileTarget); - } - } else { - $groupFileTarget = null; - } - $queriesToExecute = array(); - $queriesToExecute['groupShare'] = array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'itemTarget' => $groupItemTarget, - 'shareType' => $shareType, - 'shareWith' => $shareWith['group'], - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'shareTime' => time(), - 'fileSource' => $fileSource, - 'fileTarget' => $groupFileTarget, - 'token' => $token, - 'parent' => $parent, - 'expiration' => $expirationDate, - ); - // Loop through all users of this group in case we need to add an extra row - foreach ($shareWith['users'] as $uid) { - $itemTarget = Helper::generateTarget($itemType, $itemSource, self::SHARE_TYPE_USER, $uid, - $uidOwner, $suggestedItemTarget, $parent); - if (isset($fileSource)) { - if ($parentFolder) { - if ($parentFolder === true) { - $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $uid, - $uidOwner, $suggestedFileTarget, $parent); - if ($fileTarget != $groupFileTarget) { - $parentFolders[$uid]['folder'] = $fileTarget; - } - } else if (isset($parentFolder[$uid])) { - $fileTarget = $parentFolder[$uid]['folder'].$itemSource; - $parent = $parentFolder[$uid]['id']; - } - } else { - $fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, - $uid, $uidOwner, $suggestedFileTarget, $parent); - } - } else { - $fileTarget = null; - } - // Insert an extra row for the group share if the item or file target is unique for this user - if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) { - $queriesToExecute[] = array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'itemTarget' => $itemTarget, - 'shareType' => self::$shareTypeGroupUserUnique, - 'shareWith' => $uid, - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'shareTime' => time(), - 'fileSource' => $fileSource, - 'fileTarget' => $fileTarget, - 'token' => $token, - //'parent' => $parent, - 'expiration' => $expirationDate, - ); - } - } - - self::insertShare($queriesToExecute['groupShare']); - // Save this id, any extra rows for this group share will need to reference it - $parent = \OC_DB::insertid('*PREFIX*share'); - unset($queriesToExecute['groupShare']); - - foreach ($queriesToExecute as $shareQuery) { - $shareQuery['parent'] = $parent; - self::insertShare($shareQuery); - } - - \OC_Hook::emit('OCP\Share', 'post_shared', array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'itemTarget' => $groupItemTarget, - 'parent' => $parent, - 'shareType' => $shareType, - 'shareWith' => $shareWith['group'], - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'fileSource' => $fileSource, - 'fileTarget' => $groupFileTarget, - 'id' => $parent, - 'token' => $token, - 'expirationDate' => $expirationDate, - )); - - if ($parentFolder === true) { - // Return parent folders to preserve file target paths for potential children - return $parentFolders; - } - } else { - $itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, - $suggestedItemTarget); - $run = true; - $error = ''; - \OC_Hook::emit('OCP\Share', 'pre_shared', array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'itemTarget' => $itemTarget, - 'shareType' => $shareType, - 'shareWith' => $shareWith, - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'fileSource' => $fileSource, - 'token' => $token, - 'expirationDate' => $expirationDate, - 'run' => &$run, - 'error' => &$error, - )); - - if ($run === false) { - throw new \Exception($error); - } - - if (isset($fileSource)) { - if ($parentFolder) { - if ($parentFolder === true) { - $fileTarget = Helper::generateTarget('file', $filePath, $shareType, $shareWith, - $uidOwner, $suggestedFileTarget); - $parentFolders['folder'] = $fileTarget; - } else { - $fileTarget = $parentFolder['folder'].$itemSource; - $parent = $parentFolder['id']; - } - } else { - $fileTarget = Helper::generateTarget('file', $filePath, $shareType, $shareWith, $uidOwner, - $suggestedFileTarget); - } - } else { - $fileTarget = null; - } - - self::insertShare(array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'itemTarget' => $itemTarget, - 'shareType' => $shareType, - 'shareWith' => $shareWith, - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'shareTime' => time(), - 'fileSource' => $fileSource, - 'fileTarget' => $fileTarget, - 'token' => $token, - 'parent' => $parent, - 'expiration' => $expirationDate, - )); - - $id = \OC_DB::insertid('*PREFIX*share'); - \OC_Hook::emit('OCP\Share', 'post_shared', array( - 'itemType' => $itemType, - 'itemSource' => $itemSource, - 'itemTarget' => $itemTarget, - 'parent' => $parent, - 'shareType' => $shareType, - 'shareWith' => $shareWith, - 'uidOwner' => $uidOwner, - 'permissions' => $permissions, - 'fileSource' => $fileSource, - 'fileTarget' => $fileTarget, - 'id' => $id, - 'token' => $token, - 'expirationDate' => $expirationDate, - )); - if ($parentFolder === true) { - $parentFolders['id'] = $id; - // Return parent folder to preserve file target paths for potential children - return $parentFolders; - } - } - return true; + return $result; } private static function insertShare(array $shareData) |