Merge pull request #11898 from nextcloud/feature/read_only_public_share
Feature/read only public share
This commit is contained in:
commit
514185820e
|
@ -252,6 +252,7 @@ class ShareAPIController extends OCSController {
|
|||
|
||||
|
||||
$result['mail_send'] = $share->getMailSend() ? 1 : 0;
|
||||
$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
@ -745,6 +746,7 @@ class ShareAPIController extends OCSController {
|
|||
* @param string $publicUpload
|
||||
* @param string $expireDate
|
||||
* @param string $note
|
||||
* @param string $hideDownload
|
||||
* @return DataResponse
|
||||
* @throws LockedException
|
||||
* @throws NotFoundException
|
||||
|
@ -759,7 +761,8 @@ class ShareAPIController extends OCSController {
|
|||
string $sendPasswordByTalk = null,
|
||||
string $publicUpload = null,
|
||||
string $expireDate = null,
|
||||
string $note = null
|
||||
string $note = null,
|
||||
string $hideDownload = null
|
||||
): DataResponse {
|
||||
try {
|
||||
$share = $this->getShareById($id);
|
||||
|
@ -773,7 +776,7 @@ class ShareAPIController extends OCSController {
|
|||
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) {
|
||||
if ($permissions === null && $password === null && $sendPasswordByTalk === null && $publicUpload === null && $expireDate === null && $note === null && $hideDownload === null) {
|
||||
throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
|
||||
}
|
||||
|
||||
|
@ -786,6 +789,13 @@ class ShareAPIController extends OCSController {
|
|||
*/
|
||||
if ($share->getShareType() === Share::SHARE_TYPE_LINK) {
|
||||
|
||||
// Update hide download state
|
||||
if ($hideDownload === 'true') {
|
||||
$share->setHideDownload(true);
|
||||
} else if ($hideDownload === 'false') {
|
||||
$share->setHideDownload(false);
|
||||
}
|
||||
|
||||
$newPermissions = null;
|
||||
if ($publicUpload === 'true') {
|
||||
$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
|
||||
|
|
|
@ -321,6 +321,7 @@ class ShareController extends AuthPublicShareController {
|
|||
$shareTmpl['dir'] = '';
|
||||
$shareTmpl['nonHumanFileSize'] = $share->getNode()->getSize();
|
||||
$shareTmpl['fileSize'] = \OCP\Util::humanFileSize($share->getNode()->getSize());
|
||||
$shareTmpl['hideDownload'] = $share->getHideDownload();
|
||||
|
||||
// Show file list
|
||||
$hideFileList = false;
|
||||
|
@ -444,12 +445,14 @@ class ShareController extends AuthPublicShareController {
|
|||
$response = new PublicTemplateResponse($this->appName, 'public', $shareTmpl);
|
||||
$response->setHeaderTitle($shareTmpl['filename']);
|
||||
$response->setHeaderDetails($this->l10n->t('shared by %s', [$shareTmpl['displayName']]));
|
||||
if (!$share->getHideDownload()) {
|
||||
$response->setHeaderActions([
|
||||
new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download-white', $shareTmpl['downloadURL'], 0),
|
||||
new SimpleMenuAction('download', $this->l10n->t('Download'), 'icon-download', $shareTmpl['downloadURL'], 10, $shareTmpl['fileSize']),
|
||||
new LinkMenuAction($this->l10n->t('Direct link'), 'icon-public', $shareTmpl['previewURL']),
|
||||
new ExternalShareMenuAction($this->l10n->t('Add to your Nextcloud'), 'icon-external', $shareTmpl['owner'], $shareTmpl['displayName'], $shareTmpl['filename']),
|
||||
]);
|
||||
}
|
||||
|
||||
$response->setContentSecurityPolicy($csp);
|
||||
|
||||
|
|
|
@ -11,13 +11,16 @@
|
|||
<input type="hidden" id="filesApp" name="filesApp" value="1">
|
||||
<input type="hidden" id="isPublic" name="isPublic" value="1">
|
||||
<input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir">
|
||||
<?php if (!$_['hideDownload']): ?>
|
||||
<input type="hidden" name="downloadURL" value="<?php p($_['downloadURL']) ?>" id="downloadURL">
|
||||
<?php endif; ?>
|
||||
<input type="hidden" name="previewURL" value="<?php p($_['previewURL']) ?>" id="previewURL">
|
||||
<input type="hidden" name="sharingToken" value="<?php p($_['sharingToken']) ?>" id="sharingToken">
|
||||
<input type="hidden" name="filename" value="<?php p($_['filename']) ?>" id="filename">
|
||||
<input type="hidden" name="mimetype" value="<?php p($_['mimetype']) ?>" id="mimetype">
|
||||
<input type="hidden" name="previewSupported" value="<?php p($_['previewSupported'] ? 'true' : 'false'); ?>" id="previewSupported">
|
||||
<input type="hidden" name="mimetypeIcon" value="<?php p(\OC::$server->getMimeTypeDetector()->mimeTypeIcon($_['mimetype'])); ?>" id="mimetypeIcon">
|
||||
<input type="hidden" name="hideDownload" value="<?php p($_['hideDownload'] ? 'true' : 'false'); ?>" id="hideDownload">
|
||||
<?php
|
||||
$upload_max_filesize = OC::$server->getIniWrapper()->getBytes('upload_max_filesize');
|
||||
$post_max_size = OC::$server->getIniWrapper()->getBytes('post_max_size');
|
||||
|
@ -58,7 +61,7 @@ $maxUploadFilesize = min($upload_max_filesize, $post_max_size);
|
|||
<!-- Preview frame is filled via JS to support SVG images for modern browsers -->
|
||||
<div id="imgframe"></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($_['previewURL'] === $_['downloadURL']): ?>
|
||||
<?php if ($_['previewURL'] === $_['downloadURL'] && !$_['hideDownload']): ?>
|
||||
<div class="directDownload">
|
||||
<a href="<?php p($_['downloadURL']); ?>" id="downloadFile" class="button">
|
||||
<span class="icon icon-download"></span>
|
||||
|
|
|
@ -353,6 +353,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'note' => 'personal note',
|
||||
'displayname_file_owner' => 'ownerDisplay',
|
||||
'mimetype' => 'myMimeType',
|
||||
'hide_download' => 0,
|
||||
];
|
||||
$data[] = [$share, $expected];
|
||||
|
||||
|
@ -397,6 +398,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'note' => 'personal note',
|
||||
'displayname_file_owner' => 'ownerDisplay',
|
||||
'mimetype' => 'myFolderMimeType',
|
||||
'hide_download' => 0,
|
||||
];
|
||||
$data[] = [$share, $expected];
|
||||
|
||||
|
@ -445,6 +447,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'note' => 'personal note',
|
||||
'displayname_file_owner' => 'ownerDisplay',
|
||||
'mimetype' => 'myFolderMimeType',
|
||||
'hide_download' => 0,
|
||||
];
|
||||
$data[] = [$share, $expected];
|
||||
|
||||
|
@ -2175,6 +2178,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'note' => 'personal note',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
// User backend up
|
||||
|
@ -2204,6 +2208,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_displayname' => 'recipientDN',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [
|
||||
['owner', $owner],
|
||||
['initiator', $initiator],
|
||||
|
@ -2249,6 +2254,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_displayname' => 'recipient',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2292,6 +2298,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_displayname' => 'recipientGroupDisplayName',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2333,6 +2340,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_displayname' => 'recipientGroup2',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2377,6 +2385,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'mail_send' => 0,
|
||||
'url' => 'myLink',
|
||||
'mimetype' => 'myMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2418,6 +2427,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_displayname' => 'foobar',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myFolderMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2462,6 +2472,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_avatar' => 'path/to/the/avatar',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myFolderMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2504,6 +2515,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_avatar' => '',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myFolderMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2546,6 +2558,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_avatar' => '',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myFolderMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2603,7 +2616,8 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'mail_send' => 0,
|
||||
'mimetype' => 'myFolderMimeType',
|
||||
'password' => 'password',
|
||||
'send_password_by_talk' => false
|
||||
'send_password_by_talk' => false,
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2647,7 +2661,8 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'mail_send' => 0,
|
||||
'mimetype' => 'myFolderMimeType',
|
||||
'password' => 'password',
|
||||
'send_password_by_talk' => true
|
||||
'send_password_by_talk' => true,
|
||||
'hide_download' => 0,
|
||||
], $share, [], false
|
||||
];
|
||||
|
||||
|
@ -2787,6 +2802,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_displayname' => '',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, false, []
|
||||
];
|
||||
|
||||
|
@ -2828,6 +2844,7 @@ class ShareAPIControllerTest extends TestCase {
|
|||
'share_with_displayname' => 'recipientRoomName',
|
||||
'mail_send' => 0,
|
||||
'mimetype' => 'myMimeType',
|
||||
'hide_download' => 0,
|
||||
], $share, true, [
|
||||
'share_with_displayname' => 'recipientRoomName'
|
||||
]
|
||||
|
|
|
@ -287,7 +287,8 @@ class ShareControllerTest extends \Test\TestCase {
|
|||
'shareUrl' => null,
|
||||
'previewImage' => null,
|
||||
'previewURL' => 'downloadURL',
|
||||
'note' => $note
|
||||
'note' => $note,
|
||||
'hideDownload' => false
|
||||
);
|
||||
|
||||
$csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
|
||||
|
@ -306,6 +307,120 @@ class ShareControllerTest extends \Test\TestCase {
|
|||
$this->assertEquals($expectedResponse, $response);
|
||||
}
|
||||
|
||||
public function testShowShareHideDownload() {
|
||||
$note = 'personal note';
|
||||
|
||||
$this->shareController->setToken('token');
|
||||
|
||||
$owner = $this->getMockBuilder(IUser::class)->getMock();
|
||||
$owner->method('getDisplayName')->willReturn('ownerDisplay');
|
||||
$owner->method('getUID')->willReturn('ownerUID');
|
||||
|
||||
$file = $this->getMockBuilder('OCP\Files\File')->getMock();
|
||||
$file->method('getName')->willReturn('file1.txt');
|
||||
$file->method('getMimetype')->willReturn('text/plain');
|
||||
$file->method('getSize')->willReturn(33);
|
||||
$file->method('isReadable')->willReturn(true);
|
||||
$file->method('isShareable')->willReturn(true);
|
||||
|
||||
$share = \OC::$server->getShareManager()->newShare();
|
||||
$share->setId(42);
|
||||
$share->setPassword('password')
|
||||
->setShareOwner('ownerUID')
|
||||
->setNode($file)
|
||||
->setNote($note)
|
||||
->setTarget('/file1.txt')
|
||||
->setHideDownload(true);
|
||||
|
||||
$this->session->method('exists')->with('public_link_authenticated')->willReturn(true);
|
||||
$this->session->method('get')->with('public_link_authenticated')->willReturn('42');
|
||||
|
||||
// Even if downloads are disabled the "downloadURL" parameter is
|
||||
// provided to the template, as it is needed to preview audio and GIF
|
||||
// files.
|
||||
$this->urlGenerator->expects($this->at(0))
|
||||
->method('linkToRouteAbsolute')
|
||||
->with('files_sharing.sharecontroller.downloadShare', ['token' => 'token'])
|
||||
->willReturn('downloadURL');
|
||||
|
||||
$this->previewManager->method('isMimeSupported')->with('text/plain')->willReturn(true);
|
||||
|
||||
$this->config->method('getSystemValue')
|
||||
->willReturnMap(
|
||||
[
|
||||
['max_filesize_animated_gifs_public_sharing', 10, 10],
|
||||
['enable_previews', true, true],
|
||||
['preview_max_x', 1024, 1024],
|
||||
['preview_max_y', 1024, 1024],
|
||||
]
|
||||
);
|
||||
$shareTmpl['maxSizeAnimateGif'] = $this->config->getSystemValue('max_filesize_animated_gifs_public_sharing', 10);
|
||||
$shareTmpl['previewEnabled'] = $this->config->getSystemValue('enable_previews', true);
|
||||
|
||||
$this->shareManager
|
||||
->expects($this->once())
|
||||
->method('getShareByToken')
|
||||
->with('token')
|
||||
->willReturn($share);
|
||||
$this->config
|
||||
->expects($this->once())
|
||||
->method('getAppValue')
|
||||
->with('core', 'shareapi_public_link_disclaimertext', null)
|
||||
->willReturn('My disclaimer text');
|
||||
|
||||
$this->userManager->method('get')->with('ownerUID')->willReturn($owner);
|
||||
|
||||
$this->eventDispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with('OCA\Files_Sharing::loadAdditionalScripts');
|
||||
|
||||
$this->l10n->expects($this->any())
|
||||
->method('t')
|
||||
->will($this->returnCallback(function($text, $parameters) {
|
||||
return vsprintf($text, $parameters);
|
||||
}));
|
||||
|
||||
$response = $this->shareController->showShare();
|
||||
$sharedTmplParams = array(
|
||||
'displayName' => 'ownerDisplay',
|
||||
'owner' => 'ownerUID',
|
||||
'filename' => 'file1.txt',
|
||||
'directory_path' => '/file1.txt',
|
||||
'mimetype' => 'text/plain',
|
||||
'dirToken' => 'token',
|
||||
'sharingToken' => 'token',
|
||||
'server2serversharing' => true,
|
||||
'protected' => 'true',
|
||||
'dir' => '',
|
||||
'downloadURL' => 'downloadURL',
|
||||
'fileSize' => '33 B',
|
||||
'nonHumanFileSize' => 33,
|
||||
'maxSizeAnimateGif' => 10,
|
||||
'previewSupported' => true,
|
||||
'previewEnabled' => true,
|
||||
'previewMaxX' => 1024,
|
||||
'previewMaxY' => 1024,
|
||||
'hideFileList' => false,
|
||||
'shareOwner' => 'ownerDisplay',
|
||||
'disclaimer' => 'My disclaimer text',
|
||||
'shareUrl' => null,
|
||||
'previewImage' => null,
|
||||
'previewURL' => 'downloadURL',
|
||||
'note' => $note,
|
||||
'hideDownload' => true
|
||||
);
|
||||
|
||||
$csp = new \OCP\AppFramework\Http\ContentSecurityPolicy();
|
||||
$csp->addAllowedFrameDomain('\'self\'');
|
||||
$expectedResponse = new PublicTemplateResponse($this->appName, 'public', $sharedTmplParams);
|
||||
$expectedResponse->setContentSecurityPolicy($csp);
|
||||
$expectedResponse->setHeaderTitle($sharedTmplParams['filename']);
|
||||
$expectedResponse->setHeaderDetails('shared by ' . $sharedTmplParams['displayName']);
|
||||
$expectedResponse->setHeaderActions([]);
|
||||
|
||||
$this->assertEquals($expectedResponse, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \OCP\Files\NotFoundException
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
|
||||
*
|
||||
* @author Roeland Jago Douma <roeland@famdouma.nl>
|
||||
*
|
||||
* @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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OC\Core\Migrations;
|
||||
|
||||
use Closure;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
use OCP\Migration\IOutput;
|
||||
|
||||
class Version15000Date20181015062942 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('hide_download', 'smallint', [
|
||||
'notnull' => true,
|
||||
'length' => 1,
|
||||
'default' => 0,
|
||||
]);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
|
@ -11,6 +11,16 @@
|
|||
<input id="linkText-{{cid}}" class="linkText" type="text" readonly="readonly" value="{{shareLinkURL}}" />
|
||||
</span>
|
||||
</li>
|
||||
{{#if showHideDownloadCheckbox}}
|
||||
<li>
|
||||
<span class="shareOption menuitem">
|
||||
<span class="icon-loading-small hidden"></span>
|
||||
<input type="checkbox" name="hideDownload" id="sharingDialogHideDownload-{{cid}}" class="checkbox hideDownloadCheckbox"
|
||||
{{#if hideDownload}}checked="checked"{{/if}} />
|
||||
<label for="sharingDialogHideDownload-{{cid}}">{{hideDownloadLabel}}</label>
|
||||
</span>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if publicUpload}}
|
||||
<li>
|
||||
<span class="shareOption menuitem">
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
'change .linkCheckbox': 'onLinkCheckBoxChange',
|
||||
// open menu
|
||||
'click .share-menu .icon-more': 'onToggleMenu',
|
||||
// hide download
|
||||
'change .hideDownloadCheckbox': 'onHideDownloadChange',
|
||||
// password
|
||||
'focusout input.linkPassText': 'onPasswordEntered',
|
||||
'keyup input.linkPassText': 'onPasswordKeyUp',
|
||||
|
@ -179,6 +181,20 @@
|
|||
$el.select();
|
||||
},
|
||||
|
||||
onHideDownloadChange: function() {
|
||||
var $checkbox = this.$('.hideDownloadCheckbox');
|
||||
$checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock');
|
||||
|
||||
var hideDownload = false;
|
||||
if($checkbox.is(':checked')) {
|
||||
hideDownload = true;
|
||||
}
|
||||
|
||||
this.model.saveLinkShare({
|
||||
hideDownload: hideDownload
|
||||
});
|
||||
},
|
||||
|
||||
onShowPasswordClick: function() {
|
||||
this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
|
||||
this.$el.find('.linkPassMenu').toggleClass('hidden');
|
||||
|
@ -401,6 +417,9 @@
|
|||
var passwordPlaceholderInitial = this.configModel.get('enforcePasswordForPublicLink')
|
||||
? PASSWORD_PLACEHOLDER_MESSAGE : PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL;
|
||||
|
||||
var showHideDownloadCheckbox = !this.model.isFolder();
|
||||
var hideDownload = this.model.get('linkShare').hideDownload;
|
||||
|
||||
var publicEditable =
|
||||
!this.model.isFolder()
|
||||
&& isLinkShare
|
||||
|
@ -464,6 +483,9 @@
|
|||
|
||||
shareLinkURL: this.model.get('linkShare').link,
|
||||
urlLabel: t('core', 'Link'),
|
||||
showHideDownloadCheckbox: showHideDownloadCheckbox,
|
||||
hideDownload: hideDownload,
|
||||
hideDownloadLabel: t('core', 'Hide download'),
|
||||
enablePasswordLabel: t('core', 'Password protect'),
|
||||
passwordLabel: t('core', 'Password'),
|
||||
passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
* @typedef {object} OC.Share.Types.LinkShareInfo
|
||||
* @property {bool} isLinkShare
|
||||
* @property {string} token
|
||||
* @property {bool} hideDownload
|
||||
* @property {string|null} password
|
||||
* @property {string} link
|
||||
* @property {number} permissions
|
||||
|
@ -136,6 +137,7 @@
|
|||
call = this.updateShare(shareId, attributes, options);
|
||||
} else {
|
||||
attributes = _.defaults(attributes, {
|
||||
hideDownload: false,
|
||||
password: '',
|
||||
passwordChanged: false,
|
||||
permissions: OC.PERMISSION_READ,
|
||||
|
@ -866,6 +868,9 @@
|
|||
isLinkShare: true,
|
||||
id: share.id,
|
||||
token: share.token,
|
||||
// hide_download is returned as an int, so force it
|
||||
// to a boolean
|
||||
hideDownload: !!share.hide_download,
|
||||
password: share.share_with,
|
||||
link: link,
|
||||
permissions: share.permissions,
|
||||
|
|
|
@ -61,6 +61,20 @@ templates['sharedialoglinkshareview'] = template({"1":function(container,depth0,
|
|||
templates['sharedialoglinkshareview_popover_menu'] = template({"1":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>\n <span class=\"shareOption menuitem\">\n <span class=\"icon-loading-small hidden\"></span>\n <input type=\"checkbox\" name=\"hideDownload\" id=\"sharingDialogHideDownload-"
|
||||
+ alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper)))
|
||||
+ "\" class=\"checkbox hideDownloadCheckbox\"\n "
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hideDownload : depth0),{"name":"if","hash":{},"fn":container.program(2, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " />\n <label for=\"sharingDialogHideDownload-"
|
||||
+ alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper)))
|
||||
+ "\">"
|
||||
+ alias4(((helper = (helper = helpers.hideDownloadLabel || (depth0 != null ? depth0.hideDownloadLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"hideDownloadLabel","hash":{},"data":data}) : helper)))
|
||||
+ "</label>\n </span>\n </li>\n";
|
||||
},"2":function(container,depth0,helpers,partials,data) {
|
||||
return "checked=\"checked\"";
|
||||
},"4":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>\n <span class=\"shareOption menuitem\">\n <span class=\"icon-loading-small hidden\"></span>\n <input type=\"radio\" name=\"publicUpload\" value=\""
|
||||
+ alias4(((helper = (helper = helpers.publicUploadRValue || (depth0 != null ? depth0.publicUploadRValue : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"publicUploadRValue","hash":{},"data":data}) : helper)))
|
||||
+ "\" id=\"sharingDialogAllowPublicUpload-r-"
|
||||
|
@ -92,7 +106,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont
|
|||
+ "\">"
|
||||
+ alias4(((helper = (helper = helpers.publicUploadWLabel || (depth0 != null ? depth0.publicUploadWLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"publicUploadWLabel","hash":{},"data":data}) : helper)))
|
||||
+ "</label>\n </span>\n </li>\n";
|
||||
},"3":function(container,depth0,helpers,partials,data) {
|
||||
},"6":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 id=\"allowPublicEditingWrapper\">\n <span class=\"shareOption menuitem\">\n <span class=\"icon-loading-small hidden\"></span>\n <input type=\"checkbox\" name=\"allowPublicEditing\" id=\"sharingDialogAllowPublicEditing-"
|
||||
|
@ -104,41 +118,39 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont
|
|||
+ "\">"
|
||||
+ alias4(((helper = (helper = helpers.publicEditingLabel || (depth0 != null ? depth0.publicEditingLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"publicEditingLabel","hash":{},"data":data}) : helper)))
|
||||
+ "</label>\n </span>\n </li>\n";
|
||||
},"5":function(container,depth0,helpers,partials,data) {
|
||||
},"8":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>\n <span class=\"shareOption menuitem\">\n <input type=\"checkbox\" name=\"showPassword\" id=\"showPassword-"
|
||||
+ alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper)))
|
||||
+ "\" class=\"checkbox showPasswordCheckbox\"\n "
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordSet : 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.isPasswordEnforced : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isPasswordEnforced : depth0),{"name":"if","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " value=\"1\" />\n <label for=\"showPassword-"
|
||||
+ alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper)))
|
||||
+ "\">"
|
||||
+ alias4(((helper = (helper = helpers.enablePasswordLabel || (depth0 != null ? depth0.enablePasswordLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"enablePasswordLabel","hash":{},"data":data}) : helper)))
|
||||
+ "</label>\n </span>\n </li>\n <li class=\""
|
||||
+ ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"unless","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.isPasswordSet : depth0),{"name":"unless","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " linkPassMenu\">\n <span class=\"shareOption menuitem icon-share-pass\">\n <input id=\"linkPassText-"
|
||||
+ alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper)))
|
||||
+ "\" class=\"linkPassText\" type=\"password\" placeholder=\""
|
||||
+ alias4(((helper = (helper = helpers.passwordPlaceholder || (depth0 != null ? depth0.passwordPlaceholder : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"passwordPlaceholder","hash":{},"data":data}) : helper)))
|
||||
+ "\" autocomplete=\"new-password\" />\n <span class=\"icon icon-loading-small hidden\"></span>\n </span>\n </li>\n";
|
||||
},"6":function(container,depth0,helpers,partials,data) {
|
||||
return "checked=\"checked\"";
|
||||
},"8":function(container,depth0,helpers,partials,data) {
|
||||
},"9":function(container,depth0,helpers,partials,data) {
|
||||
return "disabled=\"disabled\"";
|
||||
},"10":function(container,depth0,helpers,partials,data) {
|
||||
},"11":function(container,depth0,helpers,partials,data) {
|
||||
return "hidden";
|
||||
},"12":function(container,depth0,helpers,partials,data) {
|
||||
},"13":function(container,depth0,helpers,partials,data) {
|
||||
var helper;
|
||||
|
||||
return container.escapeExpression(((helper = (helper = helpers.expireDate || (depth0 != null ? depth0.expireDate : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"expireDate","hash":{},"data":data}) : helper)));
|
||||
},"14":function(container,depth0,helpers,partials,data) {
|
||||
},"15":function(container,depth0,helpers,partials,data) {
|
||||
var helper;
|
||||
|
||||
return container.escapeExpression(((helper = (helper = helpers.defaultExpireDate || (depth0 != null ? depth0.defaultExpireDate : depth0)) != null ? helper : helpers.helperMissing),(typeof helper === "function" ? helper.call(depth0 != null ? depth0 : (container.nullContext || {}),{"name":"defaultExpireDate","hash":{},"data":data}) : helper)));
|
||||
},"16":function(container,depth0,helpers,partials,data) {
|
||||
},"17":function(container,depth0,helpers,partials,data) {
|
||||
var helper, alias1=depth0 != null ? depth0 : (container.nullContext || {}), alias2=helpers.helperMissing, alias3="function", alias4=container.escapeExpression;
|
||||
|
||||
return " <li>\n <a href=\"#\" class=\"shareOption menuitem pop-up\" data-url=\""
|
||||
|
@ -162,21 +174,22 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont
|
|||
+ "\" class=\"linkText\" type=\"text\" readonly=\"readonly\" value=\""
|
||||
+ alias4(((helper = (helper = helpers.shareLinkURL || (depth0 != null ? depth0.shareLinkURL : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareLinkURL","hash":{},"data":data}) : helper)))
|
||||
+ "\" />\n </span>\n </li>\n"
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicUpload : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicEditing : depth0),{"name":"if","hash":{},"fn":container.program(3, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showPasswordCheckBox : depth0),{"name":"if","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showHideDownloadCheckbox : depth0),{"name":"if","hash":{},"fn":container.program(1, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.publicUpload : 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.publicEditing : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.showPasswordCheckBox : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " <li>\n <span class=\"shareOption menuitem\">\n <input id=\"expireDate-"
|
||||
+ alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper)))
|
||||
+ "\" type=\"checkbox\" name=\"expirationDate\" class=\"expireDate checkbox\"\n "
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(6, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : 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.isExpirationEnforced : depth0),{"name":"if","hash":{},"fn":container.program(8, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.isExpirationEnforced : depth0),{"name":"if","hash":{},"fn":container.program(9, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "\" />\n <label for=\"expireDate-"
|
||||
+ alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper)))
|
||||
+ "\">"
|
||||
+ alias4(((helper = (helper = helpers.expireDateLabel || (depth0 != null ? depth0.expireDateLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"expireDateLabel","hash":{},"data":data}) : helper)))
|
||||
+ "</label>\n </span>\n </li>\n <li class=\""
|
||||
+ ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"unless","hash":{},"fn":container.program(10, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers.unless.call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"unless","hash":{},"fn":container.program(11, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ "\">\n <span class=\"menuitem icon-expiredate expirationDateContainer-"
|
||||
+ alias4(((helper = (helper = helpers.cid || (depth0 != null ? depth0.cid : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"cid","hash":{},"data":data}) : helper)))
|
||||
+ "\">\n <label for=\"expirationDatePicker-"
|
||||
|
@ -190,7 +203,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont
|
|||
+ "\" class=\"datepicker\" type=\"text\" placeholder=\""
|
||||
+ alias4(((helper = (helper = helpers.expirationDatePlaceholder || (depth0 != null ? depth0.expirationDatePlaceholder : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"expirationDatePlaceholder","hash":{},"data":data}) : helper)))
|
||||
+ "\" value=\""
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(12, data, 0),"inverse":container.program(14, data, 0),"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers["if"].call(alias1,(depth0 != null ? depth0.hasExpireDate : depth0),{"name":"if","hash":{},"fn":container.program(13, data, 0),"inverse":container.program(15, data, 0),"data":data})) != null ? stack1 : "")
|
||||
+ "\" />\n </span>\n </li>\n <li>\n <a href=\"#\" class=\"share-add\">\n <span class=\"icon-loading-small hidden\"></span>\n <span class=\"icon icon-edit\"></span>\n <span>"
|
||||
+ alias4(((helper = (helper = helpers.addNoteLabel || (depth0 != null ? depth0.addNoteLabel : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"addNoteLabel","hash":{},"data":data}) : helper)))
|
||||
+ "</span>\n <input type=\"button\" class=\"share-note-delete icon-delete\">\n </a>\n </li>\n <li class=\"share-note-form share-note-link hidden\">\n <span class=\"menuitem icon-note\">\n <textarea class=\"share-note\">"
|
||||
|
@ -198,7 +211,7 @@ templates['sharedialoglinkshareview_popover_menu'] = template({"1":function(cont
|
|||
+ "</textarea>\n <input type=\"submit\" class=\"icon-confirm share-note-submit\" value=\"\" id=\"add-note-"
|
||||
+ alias4(((helper = (helper = helpers.shareId || (depth0 != null ? depth0.shareId : depth0)) != null ? helper : alias2),(typeof helper === alias3 ? helper.call(alias1,{"name":"shareId","hash":{},"data":data}) : helper)))
|
||||
+ "\" />\n </span>\n </li>\n"
|
||||
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.social : depth0),{"name":"each","hash":{},"fn":container.program(16, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ ((stack1 = helpers.each.call(alias1,(depth0 != null ? depth0.social : depth0),{"name":"each","hash":{},"fn":container.program(17, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
|
||||
+ " </ul>\n</div>\n";
|
||||
},"useData":true});
|
||||
templates['sharedialoglinkshareview_popover_menu_pending'] = template({"1":function(container,depth0,helpers,partials,data) {
|
||||
|
|
|
@ -72,6 +72,100 @@ describe('OC.Share.ShareDialogLinkShareView', function () {
|
|||
configModel.isShareWithLinkAllowed.restore();
|
||||
});
|
||||
|
||||
describe('hide download', function () {
|
||||
|
||||
var $hideDownloadCheckbox;
|
||||
var $workingIcon;
|
||||
|
||||
beforeEach(function () {
|
||||
// Needed to render the view
|
||||
configModel.isShareWithLinkAllowed.returns(true);
|
||||
|
||||
// Setting the share also triggers the rendering
|
||||
shareModel.set({
|
||||
linkShare: {
|
||||
isLinkShare: true,
|
||||
}
|
||||
});
|
||||
|
||||
$hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox');
|
||||
$workingIcon = $hideDownloadCheckbox.prev('.icon-loading-small');
|
||||
|
||||
sinon.stub(shareModel, 'saveLinkShare');
|
||||
|
||||
expect($workingIcon.hasClass('hidden')).toBeTruthy();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
shareModel.saveLinkShare.restore();
|
||||
});
|
||||
|
||||
it('is shown if the share is a file', function() {
|
||||
expect($hideDownloadCheckbox.length).toBeTruthy();
|
||||
});
|
||||
|
||||
it('is not shown if the share is a folder', function() {
|
||||
shareModel.fileInfoModel.set('mimetype', 'httpd/unix-directory');
|
||||
|
||||
// Setting the item type also triggers the rendering
|
||||
shareModel.set({
|
||||
itemType: 'folder'
|
||||
});
|
||||
|
||||
$hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox');
|
||||
|
||||
expect($hideDownloadCheckbox.length).toBeFalsy();
|
||||
});
|
||||
|
||||
it('checkbox is checked when the setting is enabled', function () {
|
||||
shareModel.set({
|
||||
linkShare: {
|
||||
isLinkShare: true,
|
||||
hideDownload: true
|
||||
}
|
||||
});
|
||||
|
||||
$hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox');
|
||||
|
||||
expect($hideDownloadCheckbox.is(':checked')).toEqual(true);
|
||||
});
|
||||
|
||||
it('checkbox is not checked when the setting is disabled', function () {
|
||||
expect($hideDownloadCheckbox.is(':checked')).toEqual(false);
|
||||
});
|
||||
|
||||
it('enables the setting if clicked when unchecked', function () {
|
||||
// Simulate the click by checking the checkbox and then triggering
|
||||
// the "change" event.
|
||||
$hideDownloadCheckbox.prop('checked', true);
|
||||
$hideDownloadCheckbox.change();
|
||||
|
||||
expect($workingIcon.hasClass('hidden')).toBeFalsy();
|
||||
expect(shareModel.saveLinkShare.withArgs({ hideDownload: true }).calledOnce).toBeTruthy();
|
||||
});
|
||||
|
||||
it('disables the setting if clicked when checked', function () {
|
||||
shareModel.set({
|
||||
linkShare: {
|
||||
isLinkShare: true,
|
||||
hideDownload: true
|
||||
}
|
||||
});
|
||||
|
||||
$hideDownloadCheckbox = view.$el.find('.hideDownloadCheckbox');
|
||||
$workingIcon = $hideDownloadCheckbox.prev('.icon-loading-small');
|
||||
|
||||
// Simulate the click by unchecking the checkbox and then triggering
|
||||
// the "change" event.
|
||||
$hideDownloadCheckbox.prop('checked', false);
|
||||
$hideDownloadCheckbox.change();
|
||||
|
||||
expect($workingIcon.hasClass('hidden')).toBeFalsy();
|
||||
expect(shareModel.saveLinkShare.withArgs({ hideDownload: false }).calledOnce).toBeTruthy();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('onPasswordEntered', function () {
|
||||
|
||||
var $passwordText;
|
||||
|
|
|
@ -168,7 +168,8 @@ describe('OC.Share.ShareItemModel', function() {
|
|||
stime: 1403884258,
|
||||
storage: 1,
|
||||
token: 'tehtoken',
|
||||
uid_owner: 'root'
|
||||
uid_owner: 'root',
|
||||
hide_download: 1
|
||||
}
|
||||
]));
|
||||
|
||||
|
@ -186,6 +187,7 @@ describe('OC.Share.ShareItemModel', function() {
|
|||
|
||||
var linkShare = model.get('linkShare');
|
||||
expect(linkShare.isLinkShare).toEqual(true);
|
||||
expect(linkShare.hideDownload).toEqual(true);
|
||||
|
||||
// TODO: check more attributes
|
||||
});
|
||||
|
@ -289,7 +291,8 @@ describe('OC.Share.ShareItemModel', function() {
|
|||
stime: 1403884258,
|
||||
storage: 1,
|
||||
token: 'tehtoken',
|
||||
uid_owner: 'root'
|
||||
uid_owner: 'root',
|
||||
hide_download: 0
|
||||
}, {
|
||||
displayname_owner: 'root',
|
||||
expiration: '2015-10-15 00:00:00',
|
||||
|
@ -307,7 +310,8 @@ describe('OC.Share.ShareItemModel', function() {
|
|||
stime: 1403884509,
|
||||
storage: 1,
|
||||
token: 'anothertoken',
|
||||
uid_owner: 'root'
|
||||
uid_owner: 'root',
|
||||
hide_download: 1
|
||||
}]
|
||||
));
|
||||
OC.currentUser = 'root';
|
||||
|
@ -320,6 +324,7 @@ describe('OC.Share.ShareItemModel', function() {
|
|||
var linkShare = model.get('linkShare');
|
||||
expect(linkShare.isLinkShare).toEqual(true);
|
||||
expect(linkShare.token).toEqual('tehtoken');
|
||||
expect(linkShare.hideDownload).toEqual(false);
|
||||
|
||||
// TODO: check child too
|
||||
});
|
||||
|
@ -579,6 +584,7 @@ describe('OC.Share.ShareItemModel', function() {
|
|||
|
||||
expect(addShareStub.calledOnce).toEqual(true);
|
||||
expect(addShareStub.firstCall.args[0]).toEqual({
|
||||
hideDownload: false,
|
||||
password: '',
|
||||
passwordChanged: false,
|
||||
permissions: OC.PERMISSION_READ,
|
||||
|
@ -603,6 +609,7 @@ describe('OC.Share.ShareItemModel', function() {
|
|||
|
||||
expect(addShareStub.calledOnce).toEqual(true);
|
||||
expect(addShareStub.firstCall.args[0]).toEqual({
|
||||
hideDownload: false,
|
||||
password: '',
|
||||
passwordChanged: false,
|
||||
permissions: OC.PERMISSION_READ,
|
||||
|
|
|
@ -652,6 +652,7 @@ return array(
|
|||
'OC\\Core\\Migrations\\Version14000Date20180710092004' => $baseDir . '/core/Migrations/Version14000Date20180710092004.php',
|
||||
'OC\\Core\\Migrations\\Version14000Date20180712153140' => $baseDir . '/core/Migrations/Version14000Date20180712153140.php',
|
||||
'OC\\Core\\Migrations\\Version15000Date20180926101451' => $baseDir . '/core/Migrations/Version15000Date20180926101451.php',
|
||||
'OC\\Core\\Migrations\\Version15000Date20181015062942' => $baseDir . '/core/Migrations/Version15000Date20181015062942.php',
|
||||
'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php',
|
||||
'OC\\DB\\AdapterMySQL' => $baseDir . '/lib/private/DB/AdapterMySQL.php',
|
||||
'OC\\DB\\AdapterOCI8' => $baseDir . '/lib/private/DB/AdapterOCI8.php',
|
||||
|
|
|
@ -682,6 +682,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\Core\\Migrations\\Version14000Date20180710092004' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180710092004.php',
|
||||
'OC\\Core\\Migrations\\Version14000Date20180712153140' => __DIR__ . '/../../..' . '/core/Migrations/Version14000Date20180712153140.php',
|
||||
'OC\\Core\\Migrations\\Version15000Date20180926101451' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20180926101451.php',
|
||||
'OC\\Core\\Migrations\\Version15000Date20181015062942' => __DIR__ . '/../../..' . '/core/Migrations/Version15000Date20181015062942.php',
|
||||
'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php',
|
||||
'OC\\DB\\AdapterMySQL' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterMySQL.php',
|
||||
'OC\\DB\\AdapterOCI8' => __DIR__ . '/../../..' . '/lib/private/DB/AdapterOCI8.php',
|
||||
|
|
|
@ -296,6 +296,7 @@ class DefaultShareProvider implements IShareProvider {
|
|||
->set('token', $qb->createNamedParameter($share->getToken()))
|
||||
->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
|
||||
->set('note', $qb->createNamedParameter($share->getNote()))
|
||||
->set('hide_download', $qb->createNamedParameter($share->getHideDownload() ? 1 : 0), IQueryBuilder::PARAM_INT)
|
||||
->execute();
|
||||
}
|
||||
|
||||
|
@ -953,6 +954,7 @@ class DefaultShareProvider implements IShareProvider {
|
|||
}
|
||||
|
||||
$share->setProviderId($this->identifier());
|
||||
$share->setHideDownload((int)$data['hide_download'] === 1);
|
||||
|
||||
return $share;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ use OCP\Files\Node;
|
|||
use OCP\Files\NotFoundException;
|
||||
use OCP\IUserManager;
|
||||
use OCP\Share\Exceptions\IllegalIDChangeException;
|
||||
use OCP\Share\IShare;
|
||||
|
||||
class Share implements \OCP\Share\IShare {
|
||||
|
||||
|
@ -85,6 +86,9 @@ class Share implements \OCP\Share\IShare {
|
|||
/** @var ICacheEntry|null */
|
||||
private $nodeCacheEntry;
|
||||
|
||||
/** @var bool */
|
||||
private $hideDownload = false;
|
||||
|
||||
public function __construct(IRootFolder $rootFolder, IUserManager $userManager) {
|
||||
$this->rootFolder = $rootFolder;
|
||||
$this->userManager = $userManager;
|
||||
|
@ -514,4 +518,13 @@ class Share implements \OCP\Share\IShare {
|
|||
public function getNodeCacheEntry() {
|
||||
return $this->nodeCacheEntry;
|
||||
}
|
||||
|
||||
public function setHideDownload(bool $hide): IShare {
|
||||
$this->hideDownload = $hide;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHideDownload(): bool {
|
||||
return $this->hideDownload;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -418,4 +418,25 @@ interface IShare {
|
|||
* @since 11.0.0
|
||||
*/
|
||||
public function getNodeCacheEntry();
|
||||
|
||||
/**
|
||||
* Sets a shares hide download state
|
||||
* This is mainly for public shares. It will signal that the share page should
|
||||
* hide download buttons etc.
|
||||
*
|
||||
* @param bool $ro
|
||||
* @return IShare
|
||||
* @since 15.0.0
|
||||
*/
|
||||
public function setHideDownload(bool $hide): IShare;
|
||||
|
||||
/**
|
||||
* Gets a shares hide download state
|
||||
* This is mainly for public shares. It will signal that the share page should
|
||||
* hide download buttons etc.
|
||||
*
|
||||
* @return bool
|
||||
* @since 15.0.0
|
||||
*/
|
||||
public function getHideDownload(): bool;
|
||||
}
|
||||
|
|
|
@ -121,6 +121,32 @@ Feature: app-files
|
|||
And I open the Share menu
|
||||
Then I see that the Share menu is shown
|
||||
|
||||
Scenario: hide download in a public shared link
|
||||
Given I act as John
|
||||
And I am logged in
|
||||
And I share the link for "welcome.txt"
|
||||
And I set the download of the shared link as hidden
|
||||
And I write down the shared link
|
||||
When I act as Jane
|
||||
And I visit the shared link I wrote down
|
||||
And I see that the current page is the shared link I wrote down
|
||||
Then I see that the download button is not shown
|
||||
And I see that the Share menu button is not shown
|
||||
|
||||
Scenario: show download again in a public shared link
|
||||
Given I act as John
|
||||
And I am logged in
|
||||
And I share the link for "welcome.txt"
|
||||
And I set the download of the shared link as hidden
|
||||
And I set the download of the shared link as shown
|
||||
And I write down the shared link
|
||||
When I act as Jane
|
||||
And I visit the shared link I wrote down
|
||||
And I see that the current page is the shared link I wrote down
|
||||
Then I see that the download button is shown
|
||||
And I open the Share menu
|
||||
And I see that the Share menu is shown
|
||||
|
||||
Scenario: creation is not possible by default in a public shared folder
|
||||
Given I act as John
|
||||
And I am logged in
|
||||
|
|
|
@ -232,6 +232,27 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
describedAs("Copy link menu item in the share link menu in the details view in Files app");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function hideDownloadCheckbox() {
|
||||
// forThe()->checkbox("Hide download") can not be used here; that would
|
||||
// return the checkbox itself, but the element that the user interacts
|
||||
// with is the label.
|
||||
return Locator::forThe()->xpath("//label[normalize-space() = 'Hide download']")->
|
||||
descendantOf(self::shareLinkMenu())->
|
||||
describedAs("Hide download checkbox in the details view in Files app");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function hideDownloadCheckboxInput() {
|
||||
return Locator::forThe()->checkbox("Hide download")->
|
||||
descendantOf(self::shareLinkMenu())->
|
||||
describedAs("Hide download checkbox input in the details view in Files app");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
|
@ -334,6 +355,28 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
$this->actor->find(self::itemInDropdownForTag($tag), 10)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I set the download of the shared link as hidden
|
||||
*/
|
||||
public function iSetTheDownloadOfTheSharedLinkAsHidden() {
|
||||
$this->showShareLinkMenuIfNeeded();
|
||||
|
||||
$this->iSeeThatTheDownloadOfTheLinkShareIsShown();
|
||||
|
||||
$this->actor->find(self::hideDownloadCheckbox(), 2)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I set the download of the shared link as shown
|
||||
*/
|
||||
public function iSetTheDownloadOfTheSharedLinkAsShown() {
|
||||
$this->showShareLinkMenuIfNeeded();
|
||||
|
||||
$this->iSeeThatTheDownloadOfTheLinkShareIsHidden();
|
||||
|
||||
$this->actor->find(self::hideDownloadCheckbox(), 2)->click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I set the shared link as editable
|
||||
*/
|
||||
|
@ -460,6 +503,24 @@ class FilesAppContext implements Context, ActorAwareInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the download of the link share is hidden
|
||||
*/
|
||||
public function iSeeThatTheDownloadOfTheLinkShareIsHidden() {
|
||||
$this->showShareLinkMenuIfNeeded();
|
||||
|
||||
PHPUnit_Framework_Assert::assertTrue($this->actor->find(self::hideDownloadCheckboxInput(), 10)->isChecked());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the download of the link share is shown
|
||||
*/
|
||||
public function iSeeThatTheDownloadOfTheLinkShareIsShown() {
|
||||
$this->showShareLinkMenuIfNeeded();
|
||||
|
||||
PHPUnit_Framework_Assert::assertFalse($this->actor->find(self::hideDownloadCheckboxInput(), 10)->isChecked());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the working icon for password protect is shown
|
||||
*/
|
||||
|
|
|
@ -103,6 +103,14 @@ class FilesSharingAppContext implements Context, ActorAwareInterface {
|
|||
describedAs("Text preview in Shared file page");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Locator
|
||||
*/
|
||||
public static function downloadButton() {
|
||||
return Locator::forThe()->id("downloadFile")->
|
||||
describedAs("Download button in Shared file page");
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I visit the shared link I wrote down
|
||||
*/
|
||||
|
@ -198,6 +206,17 @@ class FilesSharingAppContext implements Context, ActorAwareInterface {
|
|||
$this->actor->find(self::saveItemInShareMenu())->isVisible());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the Share menu button is not shown
|
||||
*/
|
||||
public function iSeeThatTheShareMenuButtonIsNotShown() {
|
||||
try {
|
||||
PHPUnit_Framework_Assert::assertFalse(
|
||||
$this->actor->find(self::shareMenuButton())->isVisible());
|
||||
} catch (NoSuchElementException $exception) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the shared file preview shows the text :text
|
||||
*/
|
||||
|
@ -205,4 +224,25 @@ class FilesSharingAppContext implements Context, ActorAwareInterface {
|
|||
PHPUnit_Framework_Assert::assertContains($text, $this->actor->find(self::textPreview(), 10)->getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the download button is shown
|
||||
*/
|
||||
public function iSeeThatTheDownloadButtonIsShown() {
|
||||
if (!WaitFor::elementToBeEventuallyShown(
|
||||
$this->actor, self::downloadButton(), $timeout = 10 * $this->actor->getFindTimeoutMultiplier())) {
|
||||
PHPUnit_Framework_Assert::fail("The download button is not visible yet after $timeout seconds");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I see that the download button is not shown
|
||||
*/
|
||||
public function iSeeThatTheDownloadButtonIsNotShown() {
|
||||
try {
|
||||
PHPUnit_Framework_Assert::assertFalse(
|
||||
$this->actor->find(self::downloadButton())->isVisible());
|
||||
} catch (NoSuchElementException $exception) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
|
||||
// when updating major/minor version number.
|
||||
|
||||
$OC_Version = array(15, 0, 0, 1);
|
||||
$OC_Version = array(15, 0, 0, 2);
|
||||
|
||||
// The human readable string
|
||||
$OC_VersionString = '15.0.0 alpha';
|
||||
|
|
Loading…
Reference in New Issue