diff --git a/apps/files_sharing/css/sharetabview.scss b/apps/files_sharing/css/sharetabview.scss index 0d277c58bd772..0ca99ddc8f7ae 100644 --- a/apps/files_sharing/css/sharetabview.scss +++ b/apps/files_sharing/css/sharetabview.scss @@ -51,7 +51,6 @@ top: 0px; } .shareWithConfirm, - .clipboardButton, .linkPass .icon-loading-small { position: absolute; right: 2px; @@ -74,21 +73,17 @@ .datepicker { margin-left: 35px; } - .clipboardButton { - position: relative; - top: initial; - right: initial; - padding: 0; - } .share-add { input.share-note-delete { - display: none; border: none; background-color: transparent; width: 44px !important; padding: 0; flex: 0 0 44px; margin-left: auto; + &.hidden { + display: none; + } } } // note @@ -123,6 +118,11 @@ margin-bottom: 10px; } } + + /* Border above last entry '+ Add another share' to separate it from current link settings */ + .new-share { + border-top: 1px solid var(--color-border); + } } .linkPass .icon-loading-small { margin-right: 0px; @@ -182,7 +182,7 @@ .avatar { width: 32px; height: 32px; - background-color: var(--color-background-darker); + background-color: var(--color-primary); } } .unshare img { @@ -194,31 +194,29 @@ display: flex; align-items: center; white-space: nowrap; - // can edit label - > .shareOption > label { - padding: 13px; - padding-right: 0; - } - // more menu - > .share-menu { - position: relative; + + // icons + > .icon:not(.hidden), + .share-menu > .icon:not(.hidden) { + padding: 14px; + height: 44px; + width: 44px; + opacity: .5; display: block; - .icon-more { - padding: 14px; - height: 44px; - width: 44px; - opacity: .5; - display: block; - cursor: pointer; - } + cursor: pointer; + &:hover, &:focus, &:active { - .icon-more { - opacity: .7;; - } + opacity: .7;; } } + + // more menu + > .share-menu { + position: relative; + display: block; + } } .username { padding: 0 8px; @@ -269,4 +267,4 @@ .resharerInfoView.subView { position: relative; -} \ No newline at end of file +} diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js index 68529fd882fa4..b02c6e3d9ee96 100644 --- a/apps/files_sharing/js/share.js +++ b/apps/files_sharing/js/share.js @@ -193,15 +193,15 @@ var $tr = fileList.findFileEl(fileInfoModel.get('name')); // We count email shares as link share - var hasLinkShare = shareModel.hasLinkShare(); + var hasLinkShares = shareModel.hasLinkShares(); shareModel.get('shares').forEach(function (share) { if (share.share_type === OC.Share.SHARE_TYPE_EMAIL) { - hasLinkShare = true; + hasLinkShares = true; } }); OCA.Sharing.Util._updateFileListDataAttributes(fileList, $tr, shareModel); - if (!OCA.Sharing.Util._updateFileActionIcon($tr, shareModel.hasUserShares(), hasLinkShare)) { + if (!OCA.Sharing.Util._updateFileActionIcon($tr, shareModel.hasUserShares(), hasLinkShares)) { // remove icon, if applicable OC.Share.markFileAsShared($tr, false, false); } @@ -249,15 +249,15 @@ * * @param $tr file element of the file to update * @param {boolean} hasUserShares true if a user share exists - * @param {boolean} hasLinkShare true if a link share exists + * @param {boolean} hasLinkShares true if a link share exists * * @return {boolean} true if the icon was set, false otherwise */ - _updateFileActionIcon: function($tr, hasUserShares, hasLinkShare) { + _updateFileActionIcon: function($tr, hasUserShares, hasLinkShares) { // if the statuses are loaded already, use them for the icon // (needed when scrolling to the next page) - if (hasUserShares || hasLinkShare || $tr.attr('data-share-recipient-data') || $tr.attr('data-share-owner')) { - OC.Share.markFileAsShared($tr, true, hasLinkShare); + if (hasUserShares || hasLinkShares || $tr.attr('data-share-recipient-data') || $tr.attr('data-share-owner')) { + OC.Share.markFileAsShared($tr, true, hasLinkShares); return true; } return false; diff --git a/apps/files_sharing/lib/Controller/ShareAPIController.php b/apps/files_sharing/lib/Controller/ShareAPIController.php index a935189491e34..61fad5d2b148b 100644 --- a/apps/files_sharing/lib/Controller/ShareAPIController.php +++ b/apps/files_sharing/lib/Controller/ShareAPIController.php @@ -160,6 +160,7 @@ protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = n 'token' => null, 'uid_file_owner' => $share->getShareOwner(), 'note' => $share->getNote(), + 'label' => $share->getLabel(), 'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(), ]; @@ -354,15 +355,17 @@ public function deleteShare(string $id): DataResponse { * @param string $shareWith * @param string $publicUpload * @param string $password - * @param bool $sendPasswordByTalk + * @param string $sendPasswordByTalk * @param string $expireDate + * @param string $label * * @return DataResponse - * @throws OCSNotFoundException - * @throws OCSForbiddenException + * @throws NotFoundException * @throws OCSBadRequestException * @throws OCSException - * + * @throws OCSForbiddenException + * @throws OCSNotFoundException + * @throws \OCP\Files\InvalidPathException * @suppress PhanUndeclaredClassMethod */ public function createShare( @@ -373,7 +376,8 @@ public function createShare( string $publicUpload = 'false', string $password = '', string $sendPasswordByTalk = null, - string $expireDate = '' + string $expireDate = '', + string $label = '' ): DataResponse { $share = $this->shareManager->newShare(); @@ -447,15 +451,6 @@ public function createShare( throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator')); } - /* - * For now we only allow 1 link share. - * Return the existing link share if this is a duplicate - */ - $existingShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, false, 1, 0); - if (!empty($existingShares)) { - return new DataResponse($this->formatShare($existingShares[0])); - } - if ($publicUpload === 'true') { // Check if public upload is allowed if (!$this->shareManager->shareApiLinkAllowPublicUpload()) { @@ -482,6 +477,10 @@ public function createShare( $share->setPassword($password); } + if (!empty($label)) { + $share->setLabel($label); + } + //Expire date if ($expireDate !== '') { try { @@ -746,6 +745,7 @@ public function getShares( * @param string $publicUpload * @param string $expireDate * @param string $note + * @param string $label * @param string $hideDownload * @return DataResponse * @throws LockedException @@ -762,6 +762,7 @@ public function updateShare( string $publicUpload = null, string $expireDate = null, string $note = null, + string $label = null, string $hideDownload = null ): DataResponse { try { @@ -776,7 +777,15 @@ public function updateShare( throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); } - if ($permissions === null && $password === null && $sendPasswordByTalk === null && $publicUpload === null && $expireDate === null && $note === null && $hideDownload === null) { + if ($permissions === null && + $password === null && + $sendPasswordByTalk === null && + $publicUpload === null && + $expireDate === null && + $note === null && + $label === null && + $hideDownload === null + ) { throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given')); } @@ -860,6 +869,10 @@ public function updateShare( $share->setPassword($password); } + if ($label !== null) { + $share->setLabel($label); + } + } else { if ($permissions !== null) { $permissions = (int)$permissions; diff --git a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php index bd263de3f6250..eb39dd7926fa1 100644 --- a/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php +++ b/apps/files_sharing/tests/Controller/ShareAPIControllerTest.php @@ -253,7 +253,7 @@ public function testGetGetShareNotExists() { public function createShare($id, $shareType, $sharedWith, $sharedBy, $shareOwner, $path, $permissions, $shareTime, $expiration, $parent, $target, $mail_send, $note = '', $token=null, - $password=null) { + $password=null, $label = '') { $share = $this->getMockBuilder(IShare::class)->getMock(); $share->method('getId')->willReturn($id); $share->method('getShareType')->willReturn($shareType); @@ -263,6 +263,7 @@ public function createShare($id, $shareType, $sharedWith, $sharedBy, $shareOwner $share->method('getNode')->willReturn($path); $share->method('getPermissions')->willReturn($permissions); $share->method('getNote')->willReturn($note); + $share->method('getLabel')->willReturn($label); $time = new \DateTime(); $time->setTimestamp($shareTime); $share->method('getShareTime')->willReturn($time); @@ -351,6 +352,7 @@ public function dataGetShare() { 'mail_send' => 0, 'uid_file_owner' => 'ownerId', 'note' => 'personal note', + 'label' => '', 'displayname_file_owner' => 'ownerDisplay', 'mimetype' => 'myMimeType', 'hide_download' => 0, @@ -396,6 +398,7 @@ public function dataGetShare() { 'mail_send' => 0, 'uid_file_owner' => 'ownerId', 'note' => 'personal note', + 'label' => '', 'displayname_file_owner' => 'ownerDisplay', 'mimetype' => 'myFolderMimeType', 'hide_download' => 0, @@ -419,7 +422,8 @@ public function dataGetShare() { 0, 'personal note', 'token', - 'password' + 'password', + 'first link share' ); $expected = [ 'id' => 101, @@ -445,6 +449,7 @@ public function dataGetShare() { 'url' => 'url', 'uid_file_owner' => 'ownerId', 'note' => 'personal note', + 'label' => 'first link share', 'displayname_file_owner' => 'ownerDisplay', 'mimetype' => 'myFolderMimeType', 'hide_download' => 0, @@ -2176,6 +2181,7 @@ public function dataFormatShare() { 'share_with' => 'recipient', 'share_with_displayname' => 'recipient', 'note' => 'personal note', + 'label' => null, 'mail_send' => 0, 'mimetype' => 'myMimeType', 'hide_download' => 0, @@ -2196,6 +2202,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'ownerDN', 'note' => 'personal note', + 'label' => null, 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -2242,6 +2249,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', + 'label' => null, 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -2286,6 +2294,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', + 'label' => null, 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -2328,6 +2337,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', + 'label' => null, 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -2356,6 +2366,7 @@ public function dataFormatShare() { ->setExpirationDate(new \DateTime('2001-01-02T00:00:00')) ->setToken('myToken') ->setNote('personal note') + ->setLabel('new link share') ->setId(42); $result[] = [ @@ -2372,6 +2383,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', + 'label' => 'new link share', 'path' => 'file', 'item_type' => 'file', 'storage_id' => 'storageId', @@ -2415,6 +2427,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => 'personal note', + 'label' => null, 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2459,6 +2472,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', + 'label' => null, 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2502,6 +2516,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', + 'label' => null, 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2545,6 +2560,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', + 'label' => null, 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2603,6 +2619,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', + 'label' => null, 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2648,6 +2665,7 @@ public function dataFormatShare() { 'uid_file_owner' => 'owner', 'displayname_file_owner' => 'owner', 'note' => '', + 'label' => null, 'path' => 'folder', 'item_type' => 'folder', 'storage_id' => 'storageId', @@ -2803,6 +2821,7 @@ public function dataFormatRoomShare() { 'mail_send' => 0, 'mimetype' => 'myMimeType', 'hide_download' => 0, + 'label' => '', ], $share, false, [] ]; @@ -2845,6 +2864,7 @@ public function dataFormatRoomShare() { 'mail_send' => 0, 'mimetype' => 'myMimeType', 'hide_download' => 0, + 'label' => '', ], $share, true, [ 'share_with_displayname' => 'recipientRoomName' ] diff --git a/core/Migrations/Version15000Date20181029084625.php b/core/Migrations/Version15000Date20181029084625.php new file mode 100644 index 0000000000000..f3e12ddbb9b9f --- /dev/null +++ b/core/Migrations/Version15000Date20181029084625.php @@ -0,0 +1,53 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * 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 + * along with this program. If not, see . + * + */ + +namespace OC\Core\Migrations; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\SimpleMigrationStep; +use OCP\Migration\IOutput; + +class Version15000Date20181029084625 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $table = $schema->getTable('share'); + $table->addColumn('label', 'string', [ + 'notnull' => false, + 'length' => 255, + ]); + + return $schema; + } + +} diff --git a/core/js/share/sharedialoglinkshareview.handlebars b/core/js/share/sharedialoglinkshareview.handlebars index bc7051683a2d5..64f527042903b 100644 --- a/core/js/share/sharedialoglinkshareview.handlebars +++ b/core/js/share/sharedialoglinkshareview.handlebars @@ -1,25 +1,39 @@ {{#if shareAllowed}} -