mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-02 15:38:15 +00:00
update share/upload link expiration
This commit is contained in:
@@ -51,6 +51,8 @@ class GenerateShareLink extends React.Component {
|
||||
isShowPasswordInput: shareLinkForceUsePassword ? true : false,
|
||||
isPasswordVisible: false,
|
||||
isExpireChecked: !this.isExpireDaysNoLimit,
|
||||
isExpirationEditIconShow: false,
|
||||
isEditingExpiration: false,
|
||||
setExp: 'by-days',
|
||||
expireDays: this.defaultExpireDays,
|
||||
expDate: null,
|
||||
@@ -337,6 +339,46 @@ class GenerateShareLink extends React.Component {
|
||||
return true;
|
||||
}
|
||||
|
||||
handleMouseOverExpirationEditIcon = () => {
|
||||
this.setState({isExpirationEditIconShow: true});
|
||||
}
|
||||
|
||||
handleMouseOutExpirationEditIcon = () => {
|
||||
this.setState({isExpirationEditIconShow: false});
|
||||
}
|
||||
|
||||
editingExpirationToggle = () => {
|
||||
this.setState({isEditingExpiration: !this.state.isEditingExpiration});
|
||||
}
|
||||
|
||||
updateExpiration = (e) => {
|
||||
|
||||
e.preventDefault();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
|
||||
let { setExp, expireDays, expDate } = this.state;
|
||||
|
||||
let expirationTime = '';
|
||||
if (setExp == 'by-days') {
|
||||
expirationTime = moment().add(parseInt(expireDays), 'days').format();
|
||||
} else {
|
||||
expirationTime = expDate.format();
|
||||
}
|
||||
|
||||
seafileAPI.updateShareLink(this.state.sharedLinkInfo.token, '', expirationTime).then((res) => {
|
||||
let sharedLinkInfo = new ShareLink(res.data);
|
||||
this.setState({
|
||||
sharedLinkInfo: sharedLinkInfo,
|
||||
isEditingExpiration: false,
|
||||
});
|
||||
let message = gettext('Successfully update expiration.');
|
||||
toaster.success(message);
|
||||
}).catch((error) => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
}
|
||||
|
||||
onNoticeMessageToggle = () => {
|
||||
this.setState({isNoticeMessageShow: !this.state.isNoticeMessageShow});
|
||||
}
|
||||
@@ -421,7 +463,59 @@ class GenerateShareLink extends React.Component {
|
||||
{sharedLinkInfo.expire_date && (
|
||||
<FormGroup className="mb-0">
|
||||
<dt className="text-secondary font-weight-normal">{gettext('Expiration Date:')}</dt>
|
||||
<dd>{moment(sharedLinkInfo.expire_date).format('YYYY-MM-DD HH:mm:ss')}</dd>
|
||||
{!this.state.isEditingExpiration &&
|
||||
<dd style={{width:'250px'}} onMouseEnter={this.handleMouseOverExpirationEditIcon} onMouseLeave={this.handleMouseOutExpirationEditIcon}>
|
||||
{moment(sharedLinkInfo.expire_date).format('YYYY-MM-DD HH:mm:ss')}
|
||||
{this.state.isExpirationEditIconShow && (
|
||||
<a href="#"
|
||||
role="button"
|
||||
aria-label={gettext('Edit')}
|
||||
title={gettext('Edit')}
|
||||
className="fa fa-pencil-alt attr-action-icon"
|
||||
onClick={this.editingExpirationToggle}>
|
||||
</a>
|
||||
)}
|
||||
</dd>
|
||||
}
|
||||
{this.state.isEditingExpiration &&
|
||||
<div className="ml-4">
|
||||
<FormGroup check>
|
||||
<Label check>
|
||||
<Input type="radio" name="set-exp" value="by-days" checked={this.state.setExp == 'by-days'} onChange={this.setExp} className="mr-1" />
|
||||
<span>{gettext('Expiration days')}</span>
|
||||
</Label>
|
||||
{this.state.setExp == 'by-days' && (
|
||||
<Fragment>
|
||||
<InputGroup style={{width: inputWidth}}>
|
||||
<Input type="text" value={this.state.expireDays} onChange={this.onExpireDaysChanged} />
|
||||
<InputGroupAddon addonType="append">
|
||||
<InputGroupText>{gettext('days')}</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
{!this.state.isExpireDaysNoLimit && (
|
||||
<FormText color="muted">{this.expirationLimitTip}</FormText>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</FormGroup>
|
||||
<FormGroup check>
|
||||
<Label check>
|
||||
<Input type="radio" name="set-exp" value="by-date" checked={this.state.setExp == 'by-date'} onChange={this.setExp} className="mr-1" />
|
||||
<span>{gettext('Expiration time')}</span>
|
||||
</Label>
|
||||
{this.state.setExp == 'by-date' && (
|
||||
<DateTimePicker
|
||||
inputWidth={inputWidth}
|
||||
disabledDate={this.disabledDate}
|
||||
value={this.state.expDate}
|
||||
onChange={this.onExpDateChanged}
|
||||
/>
|
||||
)}
|
||||
</FormGroup>
|
||||
<button className="btn btn-primary" onClick={this.updateExpiration}>{gettext('Update')}</button>{' '}
|
||||
<button className="btn btn-secondary" onClick={this.editingExpirationToggle}>{gettext('Cancel')}</button>
|
||||
</div>
|
||||
}
|
||||
</FormGroup>
|
||||
)}
|
||||
|
||||
|
@@ -50,6 +50,8 @@ class GenerateUploadLink extends React.Component {
|
||||
sharedUploadInfo: null,
|
||||
isSendLinkShown: false,
|
||||
isExpireChecked: !this.isExpireDaysNoLimit,
|
||||
isExpirationEditIconShow: false,
|
||||
isEditingExpiration: false,
|
||||
setExp: 'by-days',
|
||||
expireDays: this.defaultExpireDays,
|
||||
expDate: null
|
||||
@@ -195,11 +197,11 @@ class GenerateUploadLink extends React.Component {
|
||||
this.setState({isExpireChecked: e.target.checked});
|
||||
}
|
||||
|
||||
setExp = (e) => {
|
||||
this.setState({
|
||||
setExp: e.target.value
|
||||
});
|
||||
}
|
||||
setExp = (e) => {
|
||||
this.setState({
|
||||
setExp: e.target.value
|
||||
});
|
||||
}
|
||||
|
||||
disabledDate = (current) => {
|
||||
if (!current) {
|
||||
@@ -240,6 +242,46 @@ class GenerateUploadLink extends React.Component {
|
||||
this.props.closeShareDialog();
|
||||
}
|
||||
|
||||
handleMouseOverExpirationEditIcon = () => {
|
||||
this.setState({isExpirationEditIconShow: true});
|
||||
}
|
||||
|
||||
handleMouseOutExpirationEditIcon = () => {
|
||||
this.setState({isExpirationEditIconShow: false});
|
||||
}
|
||||
|
||||
editExpirationToggle = () => {
|
||||
this.setState({isEditingExpiration: !this.state.isEditingExpiration});
|
||||
}
|
||||
|
||||
updateExpiration = (e) => {
|
||||
|
||||
e.preventDefault();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
|
||||
let { setExp, expireDays, expDate } = this.state;
|
||||
|
||||
let expirationTime = '';
|
||||
if (setExp == 'by-days') {
|
||||
expirationTime = moment().add(parseInt(expireDays), 'days').format();
|
||||
} else {
|
||||
expirationTime = expDate.format();
|
||||
}
|
||||
|
||||
seafileAPI.updateUploadLink(this.state.sharedUploadInfo.token, expirationTime).then((res) => {
|
||||
let sharedUploadInfo = new UploadLink(res.data);
|
||||
this.setState({
|
||||
sharedUploadInfo: sharedUploadInfo,
|
||||
isEditingExpiration: false,
|
||||
});
|
||||
let message = gettext('Successfully update expiration.');
|
||||
toaster.success(message);
|
||||
}).catch((error) => {
|
||||
let errMessage = Utils.getErrorMsg(error);
|
||||
toaster.danger(errMessage);
|
||||
});
|
||||
}
|
||||
|
||||
deleteUploadLink = () => {
|
||||
let sharedUploadInfo = this.state.sharedUploadInfo;
|
||||
seafileAPI.deleteUploadLink(sharedUploadInfo.token).then(() => {
|
||||
@@ -302,7 +344,59 @@ class GenerateUploadLink extends React.Component {
|
||||
{sharedUploadInfo.expire_date && (
|
||||
<FormGroup className="mb-0">
|
||||
<dt className="text-secondary font-weight-normal">{gettext('Expiration Date:')}</dt>
|
||||
<dd>{moment(sharedUploadInfo.expire_date).format('YYYY-MM-DD HH:mm:ss')}</dd>
|
||||
{!this.state.isEditingExpiration &&
|
||||
<dd style={{width:'250px'}} onMouseEnter={this.handleMouseOverExpirationEditIcon} onMouseLeave={this.handleMouseOutExpirationEditIcon}>
|
||||
{moment(sharedUploadInfo.expire_date).format('YYYY-MM-DD HH:mm:ss')}
|
||||
{this.state.isExpirationEditIconShow && (
|
||||
<a href="#"
|
||||
role="button"
|
||||
aria-label={gettext('Edit')}
|
||||
title={gettext('Edit')}
|
||||
className="fa fa-pencil-alt attr-action-icon"
|
||||
onClick={this.editExpirationToggle}>
|
||||
</a>
|
||||
)}
|
||||
</dd>
|
||||
}
|
||||
{this.state.isEditingExpiration &&
|
||||
<div className="ml-4">
|
||||
<FormGroup check>
|
||||
<Label check>
|
||||
<Input type="radio" name="set-exp" value="by-days" checked={this.state.setExp == 'by-days'} onChange={this.setExp} className="mr-1" />
|
||||
<span>{gettext('Expiration days')}</span>
|
||||
</Label>
|
||||
{this.state.setExp == 'by-days' && (
|
||||
<Fragment>
|
||||
<InputGroup style={{width: inputWidth}}>
|
||||
<Input type="text" value={this.state.expireDays} onChange={this.onExpireDaysChanged} />
|
||||
<InputGroupAddon addonType="append">
|
||||
<InputGroupText>{gettext('days')}</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
{!this.state.isExpireDaysNoLimit && (
|
||||
<FormText color="muted">{this.expirationLimitTip}</FormText>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</FormGroup>
|
||||
<FormGroup check>
|
||||
<Label check>
|
||||
<Input type="radio" name="set-exp" value="by-date" checked={this.state.setExp == 'by-date'} onChange={this.setExp} className="mr-1" />
|
||||
<span>{gettext('Expiration time')}</span>
|
||||
</Label>
|
||||
{this.state.setExp == 'by-date' && (
|
||||
<DateTimePicker
|
||||
inputWidth={inputWidth}
|
||||
disabledDate={this.disabledDate}
|
||||
value={this.state.expDate}
|
||||
onChange={this.onExpDateChanged}
|
||||
/>
|
||||
)}
|
||||
</FormGroup>
|
||||
<button className="btn btn-primary" onClick={this.updateExpiration}>{gettext('Update')}</button>{' '}
|
||||
<button className="btn btn-secondary" onClick={this.editExpirationToggle}>{gettext('Cancel')}</button>
|
||||
</div>
|
||||
}
|
||||
</FormGroup>
|
||||
)}
|
||||
</Form>
|
||||
|
@@ -447,19 +447,12 @@ class ShareLink(APIView):
|
||||
return Response(link_info)
|
||||
|
||||
def put(self, request, token):
|
||||
""" Update share link, currently only available for permission.
|
||||
""" Update share link's permission and expiration.
|
||||
|
||||
Permission checking:
|
||||
share link creater
|
||||
"""
|
||||
|
||||
# argument check
|
||||
try:
|
||||
perm = check_permissions_arg(request)
|
||||
except Exception:
|
||||
error_msg = 'permissions invalud.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
# resource check
|
||||
try:
|
||||
fs = FileShare.objects.get(token=token)
|
||||
@@ -500,26 +493,102 @@ class ShareLink(APIView):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
if repo_folder_permission in (PERMISSION_PREVIEW_EDIT, PERMISSION_PREVIEW) \
|
||||
and perm != FileShare.PERM_VIEW_ONLY:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
# argument check
|
||||
permissions = request.data.get('permissions', '')
|
||||
if permissions:
|
||||
try:
|
||||
perm = check_permissions_arg(request)
|
||||
except Exception:
|
||||
error_msg = 'permissions invalud.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if repo_folder_permission in (PERMISSION_READ) \
|
||||
and perm not in (FileShare.PERM_VIEW_DL, FileShare.PERM_VIEW_ONLY):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
if fs.s_type == 'f':
|
||||
file_name = os.path.basename(fs.path.rstrip('/'))
|
||||
can_edit, error_msg = can_edit_file(file_name, dirent.size, repo)
|
||||
if not can_edit and perm in (FileShare.PERM_EDIT_DL, FileShare.PERM_EDIT_ONLY):
|
||||
if repo_folder_permission in (PERMISSION_PREVIEW_EDIT, PERMISSION_PREVIEW) \
|
||||
and perm != FileShare.PERM_VIEW_ONLY:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
# update share link permission
|
||||
fs.permission = perm
|
||||
fs.save()
|
||||
if repo_folder_permission in (PERMISSION_READ) \
|
||||
and perm not in (FileShare.PERM_VIEW_DL, FileShare.PERM_VIEW_ONLY):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
if fs.s_type == 'f':
|
||||
file_name = os.path.basename(fs.path.rstrip('/'))
|
||||
can_edit, error_msg = can_edit_file(file_name, dirent.size, repo)
|
||||
if not can_edit and perm in (FileShare.PERM_EDIT_DL, FileShare.PERM_EDIT_ONLY):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
# update share link permission
|
||||
fs.permission = perm
|
||||
fs.save()
|
||||
|
||||
expire_days = request.data.get('expire_days', '')
|
||||
expiration_time = request.data.get('expiration_time', '')
|
||||
|
||||
if expire_days and expiration_time:
|
||||
error_msg = 'Can not pass expire_days and expiration_time at the same time.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if expire_days:
|
||||
|
||||
try:
|
||||
expire_days = int(expire_days)
|
||||
except ValueError:
|
||||
error_msg = 'expire_days invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if expire_days <= 0:
|
||||
error_msg = 'expire_days invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if SHARE_LINK_EXPIRE_DAYS_MIN > 0:
|
||||
if expire_days < SHARE_LINK_EXPIRE_DAYS_MIN:
|
||||
error_msg = _('Expire days should be greater or equal to %s') % \
|
||||
SHARE_LINK_EXPIRE_DAYS_MIN
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if SHARE_LINK_EXPIRE_DAYS_MAX > 0:
|
||||
if expire_days > SHARE_LINK_EXPIRE_DAYS_MAX:
|
||||
error_msg = _('Expire days should be less than or equal to %s') % \
|
||||
SHARE_LINK_EXPIRE_DAYS_MAX
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
expire_date = timezone.now() + relativedelta(days=expire_days)
|
||||
fs.expire_date = expire_date
|
||||
fs.save()
|
||||
|
||||
if expiration_time:
|
||||
|
||||
try:
|
||||
expire_date = dateutil.parser.isoparse(expiration_time)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
error_msg = 'expiration_time invalid, should be iso format, for example: 2020-05-17T10:26:22+08:00'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
expire_date = expire_date.astimezone(get_current_timezone()).replace(tzinfo=None)
|
||||
|
||||
if SHARE_LINK_EXPIRE_DAYS_MIN > 0:
|
||||
expire_date_min_limit = timezone.now() + relativedelta(days=SHARE_LINK_EXPIRE_DAYS_MIN)
|
||||
expire_date_min_limit = expire_date_min_limit.replace(hour=0).replace(minute=0).replace(second=0)
|
||||
|
||||
if expire_date < expire_date_min_limit:
|
||||
error_msg = _('Expiration time should be later than %s.') % \
|
||||
expire_date_min_limit.strftime("%Y-%m-%d %H:%M:%S")
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if SHARE_LINK_EXPIRE_DAYS_MAX > 0:
|
||||
expire_date_max_limit = timezone.now() + relativedelta(days=SHARE_LINK_EXPIRE_DAYS_MAX)
|
||||
expire_date_max_limit = expire_date_max_limit.replace(hour=23).replace(minute=59).replace(second=59)
|
||||
|
||||
if expire_date > expire_date_max_limit:
|
||||
error_msg = _('Expiration time should be earlier than %s.') % \
|
||||
expire_date_max_limit.strftime("%Y-%m-%d %H:%M:%S")
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
fs.expire_date = expire_date
|
||||
fs.save()
|
||||
|
||||
link_info = get_share_link_info(fs)
|
||||
return Response(link_info)
|
||||
|
@@ -294,6 +294,88 @@ class UploadLink(APIView):
|
||||
link_info = get_upload_link_info(uls)
|
||||
return Response(link_info)
|
||||
|
||||
def put(self, request, token):
|
||||
""" Update upload link's expiration.
|
||||
|
||||
Permission checking:
|
||||
upload link creater
|
||||
"""
|
||||
|
||||
try:
|
||||
uls = UploadLinkShare.objects.get(token=token)
|
||||
except UploadLinkShare.DoesNotExist:
|
||||
error_msg = 'token %s not found.' % token
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
|
||||
expire_days = request.data.get('expire_days', '')
|
||||
expiration_time = request.data.get('expiration_time', '')
|
||||
if expire_days and expiration_time:
|
||||
error_msg = 'Can not pass expire_days and expiration_time at the same time.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
expire_date = None
|
||||
if expire_days:
|
||||
try:
|
||||
expire_days = int(expire_days)
|
||||
except ValueError:
|
||||
error_msg = 'expire_days invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if expire_days <= 0:
|
||||
error_msg = 'expire_days invalid.'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if UPLOAD_LINK_EXPIRE_DAYS_MIN > 0:
|
||||
if expire_days < UPLOAD_LINK_EXPIRE_DAYS_MIN:
|
||||
error_msg = _('Expire days should be greater or equal to %s') % \
|
||||
UPLOAD_LINK_EXPIRE_DAYS_MIN
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if UPLOAD_LINK_EXPIRE_DAYS_MAX > 0:
|
||||
if expire_days > UPLOAD_LINK_EXPIRE_DAYS_MAX:
|
||||
error_msg = _('Expire days should be less than or equal to %s') % \
|
||||
UPLOAD_LINK_EXPIRE_DAYS_MAX
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
expire_date = timezone.now() + relativedelta(days=expire_days)
|
||||
uls.expire_date = expire_date
|
||||
uls.save()
|
||||
|
||||
elif expiration_time:
|
||||
|
||||
try:
|
||||
expire_date = dateutil.parser.isoparse(expiration_time)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
error_msg = 'expiration_time invalid, should be iso format, for example: 2020-05-17T10:26:22+08:00'
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
expire_date = expire_date.astimezone(get_current_timezone()).replace(tzinfo=None)
|
||||
|
||||
if UPLOAD_LINK_EXPIRE_DAYS_MIN > 0:
|
||||
expire_date_min_limit = timezone.now() + relativedelta(days=UPLOAD_LINK_EXPIRE_DAYS_MIN)
|
||||
expire_date_min_limit = expire_date_min_limit.replace(hour=0).replace(minute=0).replace(second=0)
|
||||
|
||||
if expire_date < expire_date_min_limit:
|
||||
error_msg = _('Expiration time should be later than %s.') % \
|
||||
expire_date_min_limit.strftime("%Y-%m-%d %H:%M:%S")
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
if UPLOAD_LINK_EXPIRE_DAYS_MAX > 0:
|
||||
expire_date_max_limit = timezone.now() + relativedelta(days=UPLOAD_LINK_EXPIRE_DAYS_MAX)
|
||||
expire_date_max_limit = expire_date_max_limit.replace(hour=23).replace(minute=59).replace(second=59)
|
||||
|
||||
if expire_date > expire_date_max_limit:
|
||||
error_msg = _('Expiration time should be earlier than %s.') % \
|
||||
expire_date_max_limit.strftime("%Y-%m-%d %H:%M:%S")
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||
|
||||
uls.expire_date = expire_date
|
||||
uls.save()
|
||||
|
||||
link_info = get_upload_link_info(uls)
|
||||
return Response(link_info)
|
||||
|
||||
def delete(self, request, token):
|
||||
""" Delete upload link.
|
||||
|
||||
|
Reference in New Issue
Block a user