diff options
author | Roeland Jago Douma <rullzer@users.noreply.github.com> | 2018-11-04 21:08:11 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-04 21:08:11 +0100 |
commit | 72b7c9ffa00553f3c1439e824e439da8412ebfe9 (patch) | |
tree | 4ae3f715abc330c4467bee499df97dce0106bc7b | |
parent | 4ebb2090db6962846ae22aa3974714620cbe323e (diff) | |
parent | 77b95ccd12bb946cba96486d859b8241649868ca (diff) | |
download | nextcloud-server-72b7c9ffa00553f3c1439e824e439da8412ebfe9.tar.gz nextcloud-server-72b7c9ffa00553f3c1439e824e439da8412ebfe9.zip |
Merge pull request #12105 from nextcloud/using-resharing-right-to-display-shares
Shares are displayed to users with resharing rights
-rw-r--r-- | apps/files_sharing/lib/Controller/ShareAPIController.php | 84 | ||||
-rw-r--r-- | core/js/share/sharedialogshareelistview.handlebars | 4 | ||||
-rw-r--r-- | core/js/sharedialogshareelistview.js | 6 | ||||
-rw-r--r-- | core/js/shareitemmodel.js | 13 | ||||
-rw-r--r-- | core/js/sharetemplates.js | 34 | ||||
-rw-r--r-- | core/js/tests/specs/sharedialogshareelistview.js | 9 | ||||
-rw-r--r-- | lib/private/Share20/DefaultShareProvider.php | 14 |
7 files changed, 141 insertions, 23 deletions
diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index 42d0218de8c..f61b9dac58a 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -39,7 +39,6 @@ use OCP\AppFramework\OCS\OCSNotFoundException; use OCP\AppFramework\OCSController; use OCP\AppFramework\QueryException; use OCP\Constants; -use OCP\Files\Folder; use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\IConfig; @@ -242,6 +241,9 @@ class ShareAPIController extends OCSController { $shareWithStart = ($hasCircleId? strrpos($share->getSharedWith(), '[') + 1: 0); $shareWithLength = ($hasCircleId? -1: strpos($share->getSharedWith(), ' ')); + if (is_bool($shareWithLength)) { + $shareWithLength = -1; + } $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength); } else if ($share->getShareType() === Share::SHARE_TYPE_ROOM) { $result['share_with'] = $share->getSharedWith(); @@ -730,15 +732,29 @@ class ShareAPIController extends OCSController { $shares = array_merge($shares, $federatedShares); } - $formatted = []; + $formatted = $miniFormatted = []; + $resharingRight = false; foreach ($shares as $share) { + /** @var IShare $share */ try { - $formatted[] = $this->formatShare($share, $path); - } catch (NotFoundException $e) { + $format = $this->formatShare($share, $path); + $formatted[] = $format; + if ($share->getSharedBy() === $this->currentUser) { + $miniFormatted[] = $format; + } + + if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $path)) { + $resharingRight = true; + } + } catch (\Exception $e) { //Ignore share } } + if (!$resharingRight) { + $formatted = $miniFormatted; + } + if ($include_tags) { $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager()); } @@ -1122,4 +1138,64 @@ class ShareAPIController extends OCSController { return $this->serverContainer->query('\OCA\Spreed\Share\Helper\ShareAPIController'); } + + + /** + * Returns if we can find resharing rights in an IShare object for a specific user. + * + * @suppress PhanUndeclaredClassMethod + * + * @param string $userId + * @param IShare $share + * @param Node $node + * @return bool + * @throws NotFoundException + * @throws \OCP\Files\InvalidPathException + */ + private function shareProviderResharingRights(string $userId, IShare $share, $node): bool { + + if ($share->getShareOwner() === $userId) { + return true; + } + + // we check that current user have parent resharing rights on the current file + if ($node !== null && ($node->getPermissions() & \OCP\Constants::PERMISSION_SHARE) !== 0) { + return true; + } + + if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) { + return false; + } + + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() === $userId) { + return true; + } + + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) { + return true; + } + + if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles') && + class_exists('\OCA\Circles\Api\v1\Circles')) { + $hasCircleId = (substr($share->getSharedWith(), -1) === ']'); + $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0); + $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' ')); + if (is_bool($shareWithLength)) { + $shareWithLength = -1; + } + $sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength); + try { + $member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1); + if ($member->getLevel() >= 4) { + return true; + } + return false; + } catch (QueryException $e) { + return false; + } + } + + return false; + } + } diff --git a/core/js/share/sharedialogshareelistview.handlebars b/core/js/share/sharedialogshareelistview.handlebars index 92c07f80290..18ff219c12a 100644 --- a/core/js/share/sharedialogshareelistview.handlebars +++ b/core/js/share/sharedialogshareelistview.handlebars @@ -1,8 +1,10 @@ <ul id="shareWithList" class="shareWithList"> {{#each sharees}} + {{#unless isShareWithCurrentUser}} <li data-share-id="{{shareId}}" data-share-type="{{shareType}}" data-share-with="{{shareWith}}"> <div class="avatar {{#if modSeed}}imageplaceholderseed{{/if}}" data-username="{{shareWith}}" data-avatar="{{shareWithAvatar}}" data-displayname="{{shareWithDisplayName}}" {{#if modSeed}}data-seed="{{shareWith}} {{shareType}}"{{/if}}></div> <span class="username" title="{{shareWithTitle}}">{{shareWithDisplayName}}</span> + {{#if canUpdateShareSettings }} <span class="sharingOptionsGroup"> {{#if editPermissionPossible}} <span> @@ -14,7 +16,9 @@ {{{popoverMenu}}} </div> </span> + {{/if}} </li> + {{/unless}} {{/each}} {{#each linkReshares}} <li data-share-id="{{shareId}}" data-share-type="{{shareType}}"> diff --git a/core/js/sharedialogshareelistview.js b/core/js/sharedialogshareelistview.js index 8b709f0d74d..81326cdb6cc 100644 --- a/core/js/sharedialogshareelistview.js +++ b/core/js/sharedialogshareelistview.js @@ -86,6 +86,7 @@ var shareType = this.model.getShareType(shareIndex); var sharedBy = this.model.getSharedBy(shareIndex); var sharedByDisplayName = this.model.getSharedByDisplayName(shareIndex); + var fileOwnerUid = this.model.getFileOwnerUid(shareIndex); var hasPermissionOverride = {}; if (shareType === OC.Share.SHARE_TYPE_GROUP) { @@ -143,6 +144,8 @@ hasCreatePermission: this.model.hasCreatePermission(shareIndex), hasUpdatePermission: this.model.hasUpdatePermission(shareIndex), hasDeletePermission: this.model.hasDeletePermission(shareIndex), + sharedBy: sharedBy, + sharedByDisplayName: sharedByDisplayName, shareWith: shareWith, shareWithDisplayName: shareWithDisplayName, shareWithAvatar: shareWithAvatar, @@ -150,6 +153,9 @@ shareType: shareType, shareId: this.model.get('shares')[shareIndex].id, modSeed: shareWithAvatar || (shareType !== OC.Share.SHARE_TYPE_USER && shareType !== OC.Share.SHARE_TYPE_CIRCLE && shareType !== OC.Share.SHARE_TYPE_ROOM), + owner: fileOwnerUid, + isShareWithCurrentUser: (shareType === OC.Share.SHARE_TYPE_USER && shareWith === oc_current_user), + canUpdateShareSettings: (sharedBy === oc_current_user || fileOwnerUid === oc_current_user), isRemoteShare: shareType === OC.Share.SHARE_TYPE_REMOTE, isRemoteGroupShare: shareType === OC.Share.SHARE_TYPE_REMOTE_GROUP, isNoteAvailable: shareType !== OC.Share.SHARE_TYPE_REMOTE && shareType !== OC.Share.SHARE_TYPE_REMOTE_GROUP, diff --git a/core/js/shareitemmodel.js b/core/js/shareitemmodel.js index f4ac03e1c18..2349f19092f 100644 --- a/core/js/shareitemmodel.js +++ b/core/js/shareitemmodel.js @@ -457,6 +457,19 @@ }, /** + * @param shareIndex + * @returns {string} + */ + getFileOwnerUid: function(shareIndex) { + /** @type OC.Share.Types.ShareInfo **/ + var share = this.get('shares')[shareIndex]; + if(!_.isObject(share)) { + throw "Unknown Share"; + } + return share.uid_file_owner; + }, + + /** * returns the array index of a sharee for a provided shareId * * @param shareId diff --git a/core/js/sharetemplates.js b/core/js/sharetemplates.js index 6469e264d75..0f1762c5f05 100644 --- a/core/js/sharetemplates.js +++ b/core/js/sharetemplates.js @@ -291,6 +291,10 @@ templates['sharedialogresharerinfoview'] = template({"1":function(container,dept + "\n"; },"useData":true}); templates['sharedialogshareelistview'] = template({"1":function(container,depth0,helpers,partials,data) { + var stack1; + + return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.isShareWithCurrentUser : depth0),{"name":"unless","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : ""); +},"2":function(container,depth0,helpers,partials,data) { var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " <li data-share-id=\"" @@ -300,7 +304,7 @@ templates['sharedialogshareelistview'] = template({"1":function(container,depth0 + "\" data-share-with=\"" + alias4(((helper = (helper = helpers.shareWith || (depth0 != null ? depth0.shareWith : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareWith","hash":{},"data":data}) : helper))) + "\">\n <div class=\"avatar " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.modSeed : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.modSeed : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "\" data-username=\"" + alias4(((helper = (helper = helpers.shareWith || (depth0 != null ? depth0.shareWith : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareWith","hash":{},"data":data}) : helper))) + "\" data-avatar=\"" @@ -308,19 +312,17 @@ templates['sharedialogshareelistview'] = template({"1":function(container,depth0 + "\" data-displayname=\"" + alias4(((helper = (helper = helpers.shareWithDisplayName || (depth0 != null ? depth0.shareWithDisplayName : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareWithDisplayName","hash":{},"data":data}) : helper))) + "\" " - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.modSeed : depth0),{"name":"if","hash":{},"fn":container.program(4, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.modSeed : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "></div>\n <span class=\"username\" title=\"" + alias4(((helper = (helper = helpers.shareWithTitle || (depth0 != null ? depth0.shareWithTitle : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareWithTitle","hash":{},"data":data}) : helper))) + "\">" + alias4(((helper = (helper = helpers.shareWithDisplayName || (depth0 != null ? depth0.shareWithDisplayName : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareWithDisplayName","hash":{},"data":data}) : helper))) - + "</span>\n <span class=\"sharingOptionsGroup\">\n" - + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.editPermissionPossible : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + " <div tabindex=\"0\" class=\"share-menu\"><span class=\"icon icon-more\"></span>\n " - + ((stack1 = ((helper = (helper = helpers.popoverMenu || (depth0 != null ? depth0.popoverMenu : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"popoverMenu","hash":{},"data":data}) : helper))) != null ? stack1 : "") - + "\n </div>\n </span>\n </li>\n"; -},"2":function(container,depth0,helpers,partials,data) { + + "</span>\n" + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.canUpdateShareSettings : depth0),{"name":"if","hash":{},"fn":container.program(7, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + " </li>\n"; +},"3":function(container,depth0,helpers,partials,data) { return "imageplaceholderseed"; -},"4":function(container,depth0,helpers,partials,data) { +},"5":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return "data-seed=\"" @@ -328,7 +330,15 @@ templates['sharedialogshareelistview'] = template({"1":function(container,depth0 + " " + alias4(((helper = (helper = helpers.shareType || (depth0 != null ? depth0.shareType : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareType","hash":{},"data":data}) : helper))) + "\""; -},"6":function(container,depth0,helpers,partials,data) { +},"7":function(container,depth0,helpers,partials,data) { + var stack1, helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}); + + return " <span class=\"sharingOptionsGroup\">\n" + + ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.editPermissionPossible : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + " <div tabindex=\"0\" class=\"share-menu\"><span class=\"icon icon-more\"></span>\n " + + ((stack1 = ((helper = (helper = helpers.popoverMenu || (depth0 != null ? depth0.popoverMenu : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(alias1,{"name":"popoverMenu","hash":{},"data":data}) : helper))) != null ? stack1 : "") + + "\n </div>\n </span>\n"; +},"8":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " <span>\n <input id=\"canEdit-" @@ -342,7 +352,7 @@ templates['sharedialogshareelistview'] = template({"1":function(container,depth0 + "\">" + alias4(((helper = (helper = helpers.canEditLabel || (depth0 != null ? depth0.canEditLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"canEditLabel","hash":{},"data":data}) : helper))) + "</label>\n </span>\n"; -},"8":function(container,depth0,helpers,partials,data) { +},"10":function(container,depth0,helpers,partials,data) { var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression; return " <li data-share-id=\"" @@ -363,7 +373,7 @@ templates['sharedialogshareelistview'] = template({"1":function(container,depth0 return "<ul id=\"shareWithList\" class=\"shareWithList\">\n" + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.sharees : depth0),{"name":"each","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") - + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.linkReshares : depth0),{"name":"each","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + + ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.linkReshares : depth0),{"name":"each","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "") + "</ul>\n"; },"useData":true}); templates['sharedialogshareelistview_popover_menu'] = template({"1":function(container,depth0,helpers,partials,data) { diff --git a/core/js/tests/specs/sharedialogshareelistview.js b/core/js/tests/specs/sharedialogshareelistview.js index 4f84fa0e08f..ff353404bcc 100644 --- a/core/js/tests/specs/sharedialogshareelistview.js +++ b/core/js/tests/specs/sharedialogshareelistview.js @@ -129,6 +129,7 @@ describe('OC.Share.ShareDialogShareeListView', function () { share_type: OC.Share.SHARE_TYPE_USER, share_with: 'user1', share_with_displayname: 'User One', + uid_owner: oc_current_user, itemType: 'folder' }]); shareModel.set('itemType', 'folder'); @@ -144,6 +145,7 @@ describe('OC.Share.ShareDialogShareeListView', function () { share_type: OC.Share.SHARE_TYPE_USER, share_with: 'user _.@-\'', share_with_displayname: 'User One', + uid_owner: oc_current_user, itemType: 'folder' }]); shareModel.set('itemType', 'folder'); @@ -159,6 +161,7 @@ describe('OC.Share.ShareDialogShareeListView', function () { share_type: OC.Share.SHARE_TYPE_USER, share_with: 'user1', share_with_displayname: 'User One', + uid_owner: oc_current_user, itemType: 'folder' }]); shareModel.set('itemType', 'folder'); @@ -174,6 +177,7 @@ describe('OC.Share.ShareDialogShareeListView', function () { share_type: OC.Share.SHARE_TYPE_USER, share_with: 'user _.@-\'', share_with_displayname: 'User One', + uid_owner: oc_current_user, itemType: 'folder' }]); shareModel.set('itemType', 'folder'); @@ -189,7 +193,8 @@ describe('OC.Share.ShareDialogShareeListView', function () { permissions: 1, share_type: OC.Share.SHARE_TYPE_USER, share_with: 'user1', - share_with_displayname: 'User One' + share_with_displayname: 'User One', + uid_owner: oc_current_user, }]); shareModel.set('itemType', 'folder'); listView.render(); @@ -206,6 +211,7 @@ describe('OC.Share.ShareDialogShareeListView', function () { share_type: OC.Share.SHARE_TYPE_USER, share_with: 'user1', share_with_displayname: 'User One', + uid_owner: oc_current_user, itemType: 'folder' }]); shareModel.set('itemType', 'folder'); @@ -223,6 +229,7 @@ describe('OC.Share.ShareDialogShareeListView', function () { share_type: OC.Share.SHARE_TYPE_USER, share_with: 'user1', share_with_displayname: 'User One', + uid_owner: oc_current_user, itemType: 'folder' }]); shareModel.set('itemType', 'folder'); diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 589b64fc58a..a2388012fe7 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -623,12 +623,14 @@ class DefaultShareProvider implements IShareProvider { if ($reshares === false) { $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); } else { - $qb->andWhere( - $qb->expr()->orX( - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) - ) - ); + if ($node === null) { + $qb->andWhere( + $qb->expr()->orX( + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) + ) + ); + } } if ($node !== null) { |