diff --git a/frontend/src/components/dialog/generate-upload-link.js b/frontend/src/components/dialog/generate-upload-link.js index adcf9b0472..8bf0689b87 100644 --- a/frontend/src/components/dialog/generate-upload-link.js +++ b/frontend/src/components/dialog/generate-upload-link.js @@ -1,9 +1,9 @@ -import React from 'react'; +import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import copy from 'copy-to-clipboard'; import moment from 'moment'; -import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, InputGroupText, Alert } from 'reactstrap'; -import { gettext, shareLinkPasswordMinLength, canSendShareLinkEmail } from '../../utils/constants'; +import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, InputGroupText, Alert, FormText } from 'reactstrap'; +import { gettext, shareLinkPasswordMinLength, canSendShareLinkEmail, uploadLinkExpireDaysMin, uploadLinkExpireDaysMax, uploadLinkExpireDaysDefault } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; import { Utils } from '../../utils/utils'; import UploadLink from '../../models/upload-link'; @@ -22,6 +22,24 @@ const inputWidth = Utils.isDesktop() ? 250 : 210; class GenerateUploadLink extends React.Component { constructor(props) { super(props); + + this.isExpireDaysNoLimit = (uploadLinkExpireDaysMin === 0 && uploadLinkExpireDaysMax === 0 && uploadLinkExpireDaysDefault == 0); + this.defaultExpireDays = this.isExpireDaysNoLimit ? '' : uploadLinkExpireDaysDefault; + + let expirationLimitTip = ''; + if (uploadLinkExpireDaysMin !== 0 && uploadLinkExpireDaysMax !== 0) { + expirationLimitTip = gettext('{minDays_placeholder} - {maxDays_placeholder} days') + .replace('{minDays_placeholder}', uploadLinkExpireDaysMin) + .replace('{maxDays_placeholder}', uploadLinkExpireDaysMax); + } else if (uploadLinkExpireDaysMin !== 0 && uploadLinkExpireDaysMax === 0) { + expirationLimitTip = gettext('Greater than or equal to {minDays_placeholder} days') + .replace('{minDays_placeholder}', uploadLinkExpireDaysMin); + } else if (uploadLinkExpireDaysMin === 0 && uploadLinkExpireDaysMax !== 0) { + expirationLimitTip = gettext('Less than or equal to {maxDays_placeholder} days') + .replace('{maxDays_placeholder}', uploadLinkExpireDaysMax); + } + this.expirationLimitTip = expirationLimitTip; + this.state = { showPasswordInput: false, passwordVisible: false, @@ -29,9 +47,9 @@ class GenerateUploadLink extends React.Component { passwdnew: '', sharedUploadInfo: null, isSendLinkShown: false, - isExpireChecked: false, + isExpireChecked: !this.isExpireDaysNoLimit, setExp: 'by-days', - expireDays: '', + expireDays: this.defaultExpireDays, expDate: null }; } @@ -177,7 +195,19 @@ class GenerateUploadLink extends React.Component { return false; } - return current.isBefore(moment(), 'day'); + if (this.isExpireDaysNoLimit) { + return current.isBefore(moment(), 'day'); + } + + const startDay = moment().add(uploadLinkExpireDaysMin, 'days'); + const endDay = moment().add(uploadLinkExpireDaysMax, 'days'); + if (uploadLinkExpireDaysMin !== 0 && uploadLinkExpireDaysMax !== 0) { + return current.isBefore(startDay, 'day') || current.isAfter(endDay, 'day'); + } else if (uploadLinkExpireDaysMin !== 0 && uploadLinkExpireDaysMax === 0) { + return current.isBefore(startDay, 'day'); + } else if (uploadLinkExpireDaysMin === 0 && uploadLinkExpireDaysMax !== 0) { + return current.isBefore(moment(), 'day') || current.isAfter(endDay, 'day'); + } } onExpDateChanged = (value) => { @@ -203,6 +233,8 @@ class GenerateUploadLink extends React.Component { seafileAPI.deleteUploadLink(sharedUploadInfo.token).then(() => { this.setState({ showPasswordInput: false, + expireDays: this.defaultExpireDays, + isExpireChecked: !this.isExpireDaysNoLimit, password: '', passwordnew: '', sharedUploadInfo: null, @@ -286,7 +318,11 @@ class GenerateUploadLink extends React.Component { {this.state.isExpireChecked && @@ -297,12 +333,17 @@ class GenerateUploadLink extends React.Component { {gettext('Expiration days')} {this.state.setExp == 'by-days' && ( - - - - {gettext('days')} - - + + + + + {gettext('days')} + + + {!this.state.isExpireDaysNoLimit && ( + {this.expirationLimitTip} + )} + )} diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js index 149981d494..a3af250981 100644 --- a/frontend/src/utils/constants.js +++ b/frontend/src/utils/constants.js @@ -48,6 +48,9 @@ export const shareLinkExpireDaysMin = window.app.pageOptions.shareLinkExpireDays export const shareLinkExpireDaysMax = window.app.pageOptions.shareLinkExpireDaysMax; export const sideNavFooterCustomHtml = window.app.pageOptions.sideNavFooterCustomHtml; export const shareLinkExpireDaysDefault = window.app.pageOptions.shareLinkExpireDaysDefault; +export const uploadLinkExpireDaysMin = window.app.pageOptions.uploadLinkExpireDaysMin; +export const uploadLinkExpireDaysMax = window.app.pageOptions.uploadLinkExpireDaysMax; +export const uploadLinkExpireDaysDefault = window.app.pageOptions.uploadLinkExpireDaysDefault; export const maxFileName = window.app.pageOptions.maxFileName; export const canPublishRepo = window.app.pageOptions.canPublishRepo; export const enableEncryptedLibrary = window.app.pageOptions.enableEncryptedLibrary; diff --git a/seahub/api2/endpoints/upload_links.py b/seahub/api2/endpoints/upload_links.py index a98c5667f3..a2acb649d8 100644 --- a/seahub/api2/endpoints/upload_links.py +++ b/seahub/api2/endpoints/upload_links.py @@ -29,6 +29,9 @@ from seahub.utils import gen_shared_upload_link, gen_file_upload_url from seahub.views import check_folder_permission from seahub.utils.timeutils import datetime_to_isoformat_timestr +from seahub.settings import UPLOAD_LINK_EXPIRE_DAYS_DEFAULT, \ + UPLOAD_LINK_EXPIRE_DAYS_MIN, UPLOAD_LINK_EXPIRE_DAYS_MAX + logger = logging.getLogger(__name__) def get_upload_link_info(uls): @@ -173,6 +176,18 @@ class UploadLinks(APIView): 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) elif expiration_time: @@ -186,6 +201,28 @@ class UploadLinks(APIView): 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) + + else: + if UPLOAD_LINK_EXPIRE_DAYS_DEFAULT > 0: + expire_date = timezone.now() + relativedelta(days=UPLOAD_LINK_EXPIRE_DAYS_DEFAULT) + # resource check repo = seafile_api.get_repo(repo_id) if not repo: diff --git a/seahub/settings.py b/seahub/settings.py index d5aefb851b..a6634dcb31 100644 --- a/seahub/settings.py +++ b/seahub/settings.py @@ -342,6 +342,14 @@ SHARE_LINK_EXPIRE_DAYS_MAX = 0 # 0 means no limit # greater than or equal to MIN and less than or equal to MAX SHARE_LINK_EXPIRE_DAYS_DEFAULT = 0 +# min/max expire days for an upload link +UPLOAD_LINK_EXPIRE_DAYS_MIN = 0 # 0 means no limit +UPLOAD_LINK_EXPIRE_DAYS_MAX = 0 # 0 means no limit + +# default expire days should be +# greater than or equal to MIN and less than or equal to MAX +UPLOAD_LINK_EXPIRE_DAYS_DEFAULT = 0 + # mininum length for the password of a share link SHARE_LINK_PASSWORD_MIN_LENGTH = 8 diff --git a/seahub/templates/react_app.html b/seahub/templates/react_app.html index ef2ee43aa5..b7b20cd5db 100644 --- a/seahub/templates/react_app.html +++ b/seahub/templates/react_app.html @@ -10,7 +10,10 @@ Object.assign(app.pageOptions, { shareLinkExpireDaysDefault: {{ share_link_expire_days_default }}, shareLinkExpireDaysMin: {{ share_link_expire_days_min }}, - shareLinkExpireDaysMax: {{ share_link_expire_days_max }} + shareLinkExpireDaysMax: {{ share_link_expire_days_max }}, + uploadLinkExpireDaysDefault: {{ upload_link_expire_days_default }}, + uploadLinkExpireDaysMin: {{ upload_link_expire_days_min }}, + uploadLinkExpireDaysMax: {{ upload_link_expire_days_max }} }); {% render_bundle 'app' 'js' %} diff --git a/seahub/views/__init__.py b/seahub/views/__init__.py index 279a45a4f4..657797915e 100644 --- a/seahub/views/__init__.py +++ b/seahub/views/__init__.py @@ -54,6 +54,7 @@ from seahub.settings import AVATAR_FILE_STORAGE, \ ENABLE_FOLDER_PERM, ENABLE_REPO_SNAPSHOT_LABEL, \ UNREAD_NOTIFICATIONS_REQUEST_INTERVAL, SHARE_LINK_EXPIRE_DAYS_MIN, \ SHARE_LINK_EXPIRE_DAYS_MAX, SHARE_LINK_EXPIRE_DAYS_DEFAULT, \ + UPLOAD_LINK_EXPIRE_DAYS_MIN, UPLOAD_LINK_EXPIRE_DAYS_MAX, UPLOAD_LINK_EXPIRE_DAYS_DEFAULT, \ SEAFILE_COLLAB_SERVER, ENABLE_RESET_ENCRYPTED_REPO_PASSWORD, \ ADDITIONAL_SHARE_DIALOG_NOTE, ADDITIONAL_APP_BOTTOM_LINKS, ADDITIONAL_ABOUT_DIALOG_LINKS, \ DTABLE_WEB_SERVER @@ -1153,6 +1154,9 @@ def react_fake_view(request, **kwargs): 'share_link_expire_days_default': SHARE_LINK_EXPIRE_DAYS_DEFAULT, 'share_link_expire_days_min': SHARE_LINK_EXPIRE_DAYS_MIN, 'share_link_expire_days_max': SHARE_LINK_EXPIRE_DAYS_MAX, + 'upload_link_expire_days_default': UPLOAD_LINK_EXPIRE_DAYS_DEFAULT, + 'upload_link_expire_days_min': UPLOAD_LINK_EXPIRE_DAYS_MIN, + 'upload_link_expire_days_max': UPLOAD_LINK_EXPIRE_DAYS_MAX, 'enable_encrypted_library': config.ENABLE_ENCRYPTED_LIBRARY, 'enable_repo_history_setting': config.ENABLE_REPO_HISTORY_SETTING, 'enable_reset_encrypted_repo_password': ENABLE_RESET_ENCRYPTED_REPO_PASSWORD,