Merge pull request #17725 from nextcloud/enh/share_exp_internal

Allow internal shares to have a default expiration date
This commit is contained in:
Roeland Jago Douma 2019-11-28 08:37:19 +01:00 committed by GitHub
commit 62dc320191
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 318 additions and 39 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -77,6 +77,13 @@ class Capabilities implements ICapability {
$public['expire_date']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
}
$public['expire_date_internal'] = [];
$public['expire_date_internal']['enabled'] = $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
if ($public['expire_date_internal']['enabled']) {
$public['expire_date_internal']['days'] = $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
$public['expire_date_internal']['enforced'] = $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
}
$public['send_mail'] = $this->config->getAppValue('core', 'shareapi_allow_public_notification', 'no') === 'yes';
$public['upload'] = $this->config->getAppValue('core', 'shareapi_allow_public_upload', 'yes') === 'yes';
$public['upload_files_drop'] = $public['upload'];

View File

@ -213,6 +213,28 @@ export default {
set: function(checked) {
this.updatePermissions(this.canEdit, checked)
}
},
/**
* Does the current share have an expiration date
* @returns {boolean}
*/
hasExpirationDate: {
get: function() {
return this.config.isDefaultInternalExpireDateEnforced || !!this.share.expireDate
},
set: function(enabled) {
this.share.expireDate = enabled
? this.config.defaultInternalExpirationDateString !== ''
? this.config.defaultInternalExpirationDateString
: moment().format('YYYY-MM-DD')
: ''
}
},
dateMaxEnforced() {
return this.config.isDefaultInternalExpireDateEnforced
&& moment().add(1 + this.config.defaultInternalExpireDate, 'days')
}
},

View File

@ -379,6 +379,28 @@ export default {
return t('files_sharing', 'Share link')
},
/**
* Does the current share have an expiration date
* @returns {boolean}
*/
hasExpirationDate: {
get: function() {
return this.config.isDefaultExpireDateEnforced || !!this.share.expireDate
},
set: function(enabled) {
this.share.expireDate = enabled
? this.config.defaultExpirationDateString !== ''
? this.config.defaultExpirationDateString
: moment().format('YYYY-MM-DD')
: ''
}
},
dateMaxEnforced() {
return this.config.isDefaultExpireDateEnforced
&& moment().add(1 + this.config.defaultExpireDate, 'days')
},
/**
* Is the current share password protected ?
* @returns {boolean}

View File

@ -82,23 +82,6 @@ export default {
computed: {
/**
* Does the current share have an expiration date
* @returns {boolean}
*/
hasExpirationDate: {
get: function() {
return this.config.isDefaultExpireDateEnforced || !!this.share.expireDate
},
set: function(enabled) {
this.share.expireDate = enabled
? this.config.defaultExpirationDateString !== ''
? this.config.defaultExpirationDateString
: moment().format('YYYY-MM-DD')
: ''
}
},
/**
* Does the current share have a note
* @returns {boolean}
@ -118,11 +101,6 @@ export default {
return moment().add(1, 'days')
},
dateMaxEnforced() {
return this.config.isDefaultExpireDateEnforced
&& moment().add(1 + this.config.defaultExpireDate, 'days')
},
/**
* Datepicker lang values
* https://github.com/nextcloud/nextcloud-vue/pull/146

View File

@ -58,7 +58,7 @@ export default class Config {
}
/**
* Get the default expiration date as string
* Get the default link share expiration date as string
*
* @returns {string}
* @readonly
@ -75,6 +75,24 @@ export default class Config {
return expireDateString
}
/**
* Get the default internal expiration date as string
*
* @returns {string}
* @readonly
* @memberof Config
*/
get defaultInternalExpirationDateString() {
let expireDateString = ''
if (this.isDefaultInternalExpireDateEnabled) {
const date = window.moment.utc()
const expireAfterDays = this.defaultInternalExpireDate
date.add(expireAfterDays, 'days')
expireDateString = date.format('YYYY-MM-DD')
}
return expireDateString
}
/**
* Are link shares password-enforced ?
*
@ -119,6 +137,28 @@ export default class Config {
return OC.appConfig.core.defaultExpireDateEnabled === true
}
/**
* Is internal shares expiration enforced ?
*
* @returns {boolean}
* @readonly
* @memberof Config
*/
get isDefaultInternalExpireDateEnforced() {
return OC.appConfig.core.defaultInternalExpireDateEnforced === true
}
/**
* Is there a default expiration date for new internal shares ?
*
* @returns {boolean}
* @readonly
* @memberof Config
*/
get isDefaultInternalExpireDateEnabled() {
return OC.appConfig.core.defaultInternalExpireDateEnabled === true
}
/**
* Are users on this server allowed to send shares to other servers ?
*
@ -142,7 +182,7 @@ export default class Config {
}
/**
* Get the default days to expiration
* Get the default days to link shares expiration
*
* @returns {int}
* @readonly
@ -152,6 +192,17 @@ export default class Config {
return OC.appConfig.core.defaultExpireDate
}
/**
* Get the default days to internal shares expiration
*
* @returns {int}
* @readonly
* @memberof Config
*/
get defaultInternalExpireDate() {
return OC.appConfig.core.defaultInternalExpireDate
}
/**
* Is resharing allowed ?
*

View File

@ -86,6 +86,10 @@ $(document).ready(function(){
$("#setDefaultExpireDate").toggleClass('hidden', !this.checked);
});
$('#shareapiDefaultInternalExpireDate').change(function() {
$("#setDefaultInternalExpireDate").toggleClass('hidden', !this.checked);
});
$('#publicShareDisclaimer').change(function() {
$("#publicShareDisclaimerText").toggleClass('hidden', !this.checked);
if(!this.checked) {

View File

@ -82,6 +82,9 @@ class Sharing implements ISettings {
'enableLinkPasswordByDefault' => $this->config->getAppValue('core', 'shareapi_enable_link_password_by_default', 'no'),
'shareApiDefaultPermissions' => $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL),
'shareApiDefaultPermissionsCheckboxes' => $this->getSharePermissionList(),
'shareDefaultInternalExpireDateSet' => $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no'),
'shareInternalExpireAfterNDays' => $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7'),
'shareInternalEnforceExpireDate' => $this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no'),
];
return new TemplateResponse('settings', 'settings/admin/sharing', $parameters, '');

View File

@ -37,6 +37,22 @@
value="1" <?php if ($_['shareAPIEnabled'] === 'yes') print_unescaped('checked="checked"'); ?> />
<label for="shareAPIEnabled"><?php p($l->t('Allow apps to use the Share API'));?></label><br/>
</p>
<p id="internalShareSettings" class="indent <?php if ($_['shareAPIEnabled'] === 'no') p('hidden'); ?>">
<input type="checkbox" name="shareapi_default_internal_expire_date" id="shareapiDefaultInternalExpireDate" class="checkbox"
value="1" <?php if ($_['shareDefaultInternalExpireDateSet'] === 'yes') print_unescaped('checked="checked"'); ?> />
<label for="shareapiDefaultInternalExpireDate"><?php p($l->t('Set default expiration date for non-link shares'));?></label><br/>
</p>
<p id="setDefaultInternalExpireDate" class="double-indent <?php if ($_['shareDefaultInternalExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') p('hidden');?>">
<?php p($l->t( 'Expire after ' )); ?>
<input type="text" name='shareapi_internal_expire_after_n_days' id="shareapiInternalExpireAfterNDays" placeholder="<?php p('7')?>"
value='<?php p($_['shareInternalExpireAfterNDays']) ?>' />
<?php p($l->t( 'days' )); ?>
<input type="checkbox" name="shareapi_internal_enforce_expire_date" id="shareapiInternalEnforceExpireDate" class="checkbox"
value="1" <?php if ($_['shareInternalEnforceExpireDate'] === 'yes') print_unescaped('checked="checked"'); ?> />
<label for="shareapiInternalEnforceExpireDate"><?php p($l->t('Enforce expiration date'));?></label><br/>
</p>
<p class="<?php if ($_['shareAPIEnabled'] === 'no') p('hidden');?>">
<input type="checkbox" name="shareapi_allow_links" id="allowLinks" class="checkbox"
value="1" <?php if ($_['allowLinks'] === 'yes') print_unescaped('checked="checked"'); ?> />
@ -56,7 +72,7 @@
<input type="checkbox" name="shareapi_default_expire_date" id="shareapiDefaultExpireDate" class="checkbox"
value="1" <?php if ($_['shareDefaultExpireDateSet'] === 'yes') print_unescaped('checked="checked"'); ?> />
<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date'));?></label><br/>
<label for="shareapiDefaultExpireDate"><?php p($l->t('Set default expiration date for link shares'));?></label><br/>
</p>
<p id="setDefaultExpireDate" class="double-indent <?php if ($_['allowLinks'] !== 'yes' || $_['shareDefaultExpireDateSet'] === 'no' || $_['shareAPIEnabled'] === 'no') p('hidden');?>">

View File

@ -131,6 +131,21 @@ class SharingTest extends TestCase {
->method('getAppValue')
->with('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL)
->willReturn(Constants::PERMISSION_ALL);
$this->config
->expects($this->at(14))
->method('getAppValue')
->with('core', 'shareapi_default_internal_expire_date', 'no')
->willReturn('no');
$this->config
->expects($this->at(15))
->method('getAppValue')
->with('core', 'shareapi_internal_expire_after_n_days', '7')
->willReturn('7');
$this->config
->expects($this->at(16))
->method('getAppValue')
->with('core', 'shareapi_enforce_internal_expire_date', 'no')
->willReturn('no');
$expected = new TemplateResponse(
'settings',
@ -152,7 +167,10 @@ class SharingTest extends TestCase {
'publicShareDisclaimerText' => 'Lorem ipsum',
'enableLinkPasswordByDefault' => 'yes',
'shareApiDefaultPermissions' => Constants::PERMISSION_ALL,
'shareApiDefaultPermissionsCheckboxes' => $this->invokePrivate($this->admin, 'getSharePermissionList', [])
'shareApiDefaultPermissionsCheckboxes' => $this->invokePrivate($this->admin, 'getSharePermissionList', []),
'shareDefaultInternalExpireDateSet' => 'no',
'shareInternalExpireAfterNDays' => '7',
'shareInternalEnforceExpireDate' => 'no',
],
''
);
@ -231,6 +249,21 @@ class SharingTest extends TestCase {
->method('getAppValue')
->with('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL)
->willReturn(Constants::PERMISSION_ALL);
$this->config
->expects($this->at(14))
->method('getAppValue')
->with('core', 'shareapi_default_internal_expire_date', 'no')
->willReturn('no');
$this->config
->expects($this->at(15))
->method('getAppValue')
->with('core', 'shareapi_internal_expire_after_n_days', '7')
->willReturn('7');
$this->config
->expects($this->at(16))
->method('getAppValue')
->with('core', 'shareapi_enforce_internal_expire_date', 'no')
->willReturn('no');
$expected = new TemplateResponse(
@ -253,7 +286,10 @@ class SharingTest extends TestCase {
'publicShareDisclaimerText' => 'Lorem ipsum',
'enableLinkPasswordByDefault' => 'yes',
'shareApiDefaultPermissions' => Constants::PERMISSION_ALL,
'shareApiDefaultPermissionsCheckboxes' => $this->invokePrivate($this->admin, 'getSharePermissionList', [])
'shareApiDefaultPermissionsCheckboxes' => $this->invokePrivate($this->admin, 'getSharePermissionList', []),
'shareDefaultInternalExpireDateSet' => 'no',
'shareInternalExpireAfterNDays' => '7',
'shareInternalEnforceExpireDate' => 'no',
],
''
);

View File

@ -144,9 +144,19 @@ class DefaultShareProvider implements IShareProvider {
//Set the UID of the user we share with
$qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
$qb->setValue('accepted', $qb->createNamedParameter(IShare::STATUS_PENDING));
//If an expiration date is set store it
if ($share->getExpirationDate() !== null) {
$qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime'));
}
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
//Set the GID of the group we share with
$qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
//If an expiration date is set store it
if ($share->getExpirationDate() !== null) {
$qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime'));
}
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
//set label for public link
$qb->setValue('label', $qb->createNamedParameter($share->getLabel()));

View File

@ -351,6 +351,77 @@ class Manager implements IManager {
}
}
/**
* Validate if the expiration date fits the system settings
*
* @param \OCP\Share\IShare $share The share to validate the expiration date of
* @return \OCP\Share\IShare The modified share object
* @throws GenericShareException
* @throws \InvalidArgumentException
* @throws \Exception
*/
protected function validateExpirationDateInternal(\OCP\Share\IShare $share) {
$expirationDate = $share->getExpirationDate();
if ($expirationDate !== null) {
//Make sure the expiration date is a date
$expirationDate->setTime(0, 0, 0);
$date = new \DateTime();
$date->setTime(0, 0, 0);
if ($date >= $expirationDate) {
$message = $this->l->t('Expiration date is in the past');
throw new GenericShareException($message, $message, 404);
}
}
// If expiredate is empty set a default one if there is a default
$fullId = null;
try {
$fullId = $share->getFullId();
} catch (\UnexpectedValueException $e) {
// This is a new share
}
if ($fullId === null && $expirationDate === null && $this->shareApiInternalDefaultExpireDate()) {
$expirationDate = new \DateTime();
$expirationDate->setTime(0,0,0);
$expirationDate->add(new \DateInterval('P'.$this->shareApiInternalDefaultExpireDays().'D'));
}
// If we enforce the expiration date check that is does not exceed
if ($this->shareApiInternalDefaultExpireDateEnforced()) {
if ($expirationDate === null) {
throw new \InvalidArgumentException('Expiration date is enforced');
}
$date = new \DateTime();
$date->setTime(0, 0, 0);
$date->add(new \DateInterval('P' . $this->shareApiInternalDefaultExpireDays() . 'D'));
if ($date < $expirationDate) {
$message = $this->l->t('Cant set expiration date more than %s days in the future', [$this->shareApiInternalDefaultExpireDays()]);
throw new GenericShareException($message, $message, 404);
}
}
$accepted = true;
$message = '';
\OCP\Util::emitHook('\OC\Share', 'verifyExpirationDate', [
'expirationDate' => &$expirationDate,
'accepted' => &$accepted,
'message' => &$message,
'passwordSet' => $share->getPassword() !== null,
]);
if (!$accepted) {
throw new \Exception($message);
}
$share->setExpirationDate($expirationDate);
return $share;
}
/**
* Validate if the expiration date fits the system settings
*
@ -636,8 +707,16 @@ class Manager implements IManager {
//Verify share type
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
$this->userCreateChecks($share);
//Verify the expiration date
$share = $this->validateExpirationDateInternal($share);
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
$this->groupCreateChecks($share);
//Verify the expiration date
$share = $this->validateExpirationDateInternal($share);
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
$this->linkCreateChecks($share);
$this->setLinkParent($share);
@ -653,7 +732,7 @@ class Manager implements IManager {
);
//Verify the expiration date
$this->validateExpirationDate($share);
$share = $this->validateExpirationDate($share);
//Verify the password
$this->verifyPassword($share->getPassword());
@ -850,8 +929,20 @@ class Manager implements IManager {
if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
$this->userCreateChecks($share);
if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
//Verify the expiration date
$this->validateExpirationDate($share);
$expirationDateUpdated = true;
}
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
$this->groupCreateChecks($share);
if ($share->getExpirationDate() != $originalShare->getExpirationDate()) {
//Verify the expiration date
$this->validateExpirationDate($share);
$expirationDateUpdated = true;
}
} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
$this->linkCreateChecks($share);
@ -1575,7 +1666,7 @@ class Manager implements IManager {
}
/**
* Is default expire date enabled
* Is default link expire date enabled
*
* @return bool
*/
@ -1584,7 +1675,7 @@ class Manager implements IManager {
}
/**
* Is default expire date enforced
* Is default link expire date enforced
*`
* @return bool
*/
@ -1593,15 +1684,43 @@ class Manager implements IManager {
$this->config->getAppValue('core', 'shareapi_enforce_expire_date', 'no') === 'yes';
}
/**
* Number of default expire days
*shareApiLinkAllowPublicUpload
* Number of default link expire days
* @return int
*/
public function shareApiLinkDefaultExpireDays() {
return (int)$this->config->getAppValue('core', 'shareapi_expire_after_n_days', '7');
}
/**
* Is default internal expire date enabled
*
* @return bool
*/
public function shareApiInternalDefaultExpireDate(): bool {
return $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
}
/**
* Is default expire date enforced
*`
* @return bool
*/
public function shareApiInternalDefaultExpireDateEnforced(): bool {
return $this->shareApiInternalDefaultExpireDate() &&
$this->config->getAppValue('core', 'shareapi_enforce_internal_expire_date', 'no') === 'yes';
}
/**
* Number of default expire days
* @return int
*/
public function shareApiInternalDefaultExpireDays(): int {
return (int)$this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
}
/**
* Allow public upload on link shares
*

View File

@ -149,6 +149,13 @@ class JSConfigHelper {
}
$outgoingServer2serverShareEnabled = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes') === 'yes';
$defaultInternalExpireDateEnabled = $this->config->getAppValue('core', 'shareapi_default_internal_expire_date', 'no') === 'yes';
$defaultInternalExpireDate = $defaultInternalExpireDateEnforced = null;
if ($defaultInternalExpireDateEnabled) {
$defaultInternalExpireDate = (int) $this->config->getAppValue('core', 'shareapi_internal_expire_after_n_days', '7');
$defaultInternalExpireDateEnforced = $this->config->getAppValue('core', 'shareapi_internal_enforce_expire_date', 'no') === 'yes';
}
$countOfDataLocation = 0;
$dataLocation = str_replace(\OC::$SERVERROOT .'/', '', $this->config->getSystemValue('datadirectory', ''), $countOfDataLocation);
if($countOfDataLocation !== 1 || !$this->groupManager->isAdmin($uid)) {
@ -255,7 +262,10 @@ class JSConfigHelper {
'resharingAllowed' => \OC\Share\Share::isResharingAllowed(),
'remoteShareAllowed' => $outgoingServer2serverShareEnabled,
'federatedCloudShareDoc' => $this->urlGenerator->linkToDocs('user-sharing-federated'),
'allowGroupSharing' => \OC::$server->getShareManager()->allowGroupSharing()
'allowGroupSharing' => \OC::$server->getShareManager()->allowGroupSharing(),
'defaultInternalExpireDateEnabled' => $defaultInternalExpireDateEnabled,
'defaultInternalExpireDate' => $defaultInternalExpireDate,
'defaultInternalExpireDateEnforced' => $defaultInternalExpireDateEnforced,
]
]),
"_theme" => json_encode([

View File

@ -1743,7 +1743,8 @@ class ManagerTest extends \Test\TestCase {
->with($path);
$manager->expects($this->once())
->method('validateExpirationDate')
->with($share);
->with($share)
->willReturn($share);
$manager->expects($this->once())
->method('verifyPassword')
->with('password');