Merge pull request #11898 from nextcloud/feature/read_only_public_share

Feature/read only public share
This commit is contained in:
Roeland Jago Douma 2018-10-30 19:25:44 +01:00 committed by GitHub
commit 514185820e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 556 additions and 38 deletions

View File

@ -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;

View File

@ -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']]));
$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']),
]);
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);

View File

@ -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">
<input type="hidden" name="downloadURL" value="<?php p($_['downloadURL']) ?>" id="downloadURL">
<?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>
@ -97,4 +100,4 @@ $maxUploadFilesize = min($upload_max_filesize, $post_max_size);
data-url="<?php p(\OC::$server->getURLGenerator()->linkTo('files', 'ajax/upload.php')); ?>" />
</div>
<?php endif; ?>
</div>
</div>

View File

@ -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'
]

View File

@ -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
*/

View File

@ -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;
}
}

View File

@ -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">

View File

@ -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,

View File

@ -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,

View File

@ -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) {

View File

@ -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;

View File

@ -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,

View File

@ -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',

View File

@ -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',

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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
*/

View File

@ -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) {
}
}
}

View File

@ -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';