diff --git a/frontend/src/components/dialog/generate-share-link.js b/frontend/src/components/dialog/generate-share-link.js index 7fc2bf8f49..c01337f83b 100644 --- a/frontend/src/components/dialog/generate-share-link.js +++ b/frontend/src/components/dialog/generate-share-link.js @@ -1,8 +1,8 @@ -import React, { Fragment } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import moment from 'moment'; import copy from 'copy-to-clipboard'; -import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, InputGroupText, Alert, FormText } from 'reactstrap'; +import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, Alert } from 'reactstrap'; import { isPro, gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax, shareLinkExpireDaysDefault, shareLinkForceUsePassword, shareLinkPasswordMinLength, shareLinkPasswordStrengthLevel, canSendShareLinkEmail } from '../../utils/constants'; import ShareLinkPermissionEditor from '../../components/select-editor/share-link-permission-editor'; import { seafileAPI } from '../../utils/seafile-api'; @@ -11,8 +11,8 @@ import ShareLink from '../../models/share-link'; import toaster from '../toast'; import Loading from '../loading'; import SendLink from '../send-link'; -import DateTimePicker from '../date-and-time-picker'; import SharedLink from '../shared-link'; +import SetLinkExpiration from '../set-link-expiration'; const propTypes = { itemPath: PropTypes.string.isRequired, @@ -31,20 +31,6 @@ class GenerateShareLink extends React.Component { this.isExpireDaysNoLimit = (shareLinkExpireDaysMin === 0 && shareLinkExpireDaysMax === 0 && shareLinkExpireDaysDefault == 0); this.defaultExpireDays = this.isExpireDaysNoLimit ? '' : shareLinkExpireDaysDefault; - let expirationLimitTip = ''; - if (shareLinkExpireDaysMin !== 0 && shareLinkExpireDaysMax !== 0) { - expirationLimitTip = gettext('{minDays_placeholder} - {maxDays_placeholder} days') - .replace('{minDays_placeholder}', shareLinkExpireDaysMin) - .replace('{maxDays_placeholder}', shareLinkExpireDaysMax); - } else if (shareLinkExpireDaysMin !== 0 && shareLinkExpireDaysMax === 0) { - expirationLimitTip = gettext('Greater than or equal to {minDays_placeholder} days') - .replace('{minDays_placeholder}', shareLinkExpireDaysMin); - } else if (shareLinkExpireDaysMin === 0 && shareLinkExpireDaysMax !== 0) { - expirationLimitTip = gettext('Less than or equal to {maxDays_placeholder} days') - .replace('{maxDays_placeholder}', shareLinkExpireDaysMax); - } - this.expirationLimitTip = expirationLimitTip; - this.state = { isOpIconShown: false, isValidate: false, @@ -53,7 +39,7 @@ class GenerateShareLink extends React.Component { isExpireChecked: !this.isExpireDaysNoLimit, isExpirationEditIconShow: false, isEditingExpiration: false, - setExp: 'by-days', + expType: 'by-days', expireDays: this.defaultExpireDays, expDate: null, password: '', @@ -118,33 +104,12 @@ class GenerateShareLink extends React.Component { } } - setExp = (e) => { + setExpType = (e) => { this.setState({ - setExp: e.target.value + expType: e.target.value }); } - disabledDate = (current) => { - if (!current) { - // allow empty select - return false; - } - - if (this.isExpireDaysNoLimit) { - return current.isBefore(moment(), 'day'); - } - - const startDay = moment().add(shareLinkExpireDaysMin, 'days'); - const endDay = moment().add(shareLinkExpireDaysMax, 'days'); - if (shareLinkExpireDaysMin !== 0 && shareLinkExpireDaysMax !== 0) { - return current.isBefore(startDay, 'day') || current.isAfter(endDay, 'day'); - } else if (shareLinkExpireDaysMin !== 0 && shareLinkExpireDaysMax === 0) { - return current.isBefore(startDay, 'day'); - } else if (shareLinkExpireDaysMin === 0 && shareLinkExpireDaysMax !== 0) { - return current.isBefore(moment(), 'day') || current.isAfter(endDay, 'day'); - } - } - onExpDateChanged = (value) => { this.setState({ expDate: value @@ -199,7 +164,7 @@ class GenerateShareLink extends React.Component { if (isValid) { this.setState({errorInfo: ''}); let { itemPath, repoID } = this.props; - let { password, isExpireChecked, setExp, expireDays, expDate } = this.state; + let { password, isExpireChecked, expType, expireDays, expDate } = this.state; let permissions; if (isPro) { const permissionDetails = Utils.getShareLinkPermissionObject(this.state.currentPermission).permissionDetails; @@ -207,7 +172,7 @@ class GenerateShareLink extends React.Component { } let expirationTime = ''; if (isExpireChecked) { - if (setExp == 'by-days') { + if (expType == 'by-days') { expirationTime = moment().add(parseInt(expireDays), 'days').format(); } else { expirationTime = expDate.format(); @@ -245,6 +210,7 @@ class GenerateShareLink extends React.Component { passwdnew: '', isShowPasswordInput: shareLinkForceUsePassword ? true : false, expireDays: this.defaultExpireDays, + expDate: null, isExpireChecked: !this.isExpireDaysNoLimit, errorInfo: '', sharedLinkInfo: null, @@ -266,7 +232,7 @@ class GenerateShareLink extends React.Component { } validateParamsInput = () => { - let { isShowPasswordInput, password, passwdnew, isExpireChecked, setExp, expireDays, expDate } = this.state; + let { isShowPasswordInput, password, passwdnew, isExpireChecked, expType, expireDays, expDate } = this.state; // validate password if (isShowPasswordInput) { @@ -289,7 +255,7 @@ class GenerateShareLink extends React.Component { } if (isExpireChecked) { - if (setExp == 'by-date') { + if (expType == 'by-date') { if (!expDate) { this.setState({errorInfo: gettext('Please select an expiration time')}); return false; @@ -356,10 +322,10 @@ class GenerateShareLink extends React.Component { e.preventDefault(); e.nativeEvent.stopImmediatePropagation(); - let { setExp, expireDays, expDate } = this.state; + let { expType, expireDays, expDate } = this.state; let expirationTime = ''; - if (setExp == 'by-days') { + if (expType == 'by-days') { expirationTime = moment().add(parseInt(expireDays), 'days').format(); } else { expirationTime = expDate.format(); @@ -368,8 +334,8 @@ class GenerateShareLink extends React.Component { seafileAPI.updateShareLink(this.state.sharedLinkInfo.token, '', expirationTime).then((res) => { let sharedLinkInfo = new ShareLink(res.data); this.setState({ - sharedLinkInfo: sharedLinkInfo, - isEditingExpiration: false, + sharedLinkInfo: sharedLinkInfo, + isEditingExpiration: false, }); }).catch((error) => { let errMessage = Utils.getErrorMsg(error); @@ -413,7 +379,7 @@ class GenerateShareLink extends React.Component { let passwordLengthTip = gettext('(at least {passwordMinLength} characters and includes {passwordStrengthLevel} of the following: number, upper letter, lower letter and other symbols)'); passwordLengthTip = passwordLengthTip.replace('{passwordMinLength}', shareLinkPasswordMinLength) - .replace('{passwordStrengthLevel}', shareLinkPasswordStrengthLevel); + .replace('{passwordStrengthLevel}', shareLinkPasswordStrengthLevel); const { userPerm } = this.props; const { isCustomPermission } = Utils.getUserPermission(userPerm); @@ -463,7 +429,7 @@ class GenerateShareLink extends React.Component {
{gettext('Expiration Date:')}
{!this.state.isEditingExpiration &&
- {moment(sharedLinkInfo.expire_date).format('YYYY-MM-DD HH:mm:ss')} + {moment(sharedLinkInfo.expire_date).format('YYYY-MM-DD HH:mm:ss')} {this.state.isExpirationEditIconShow && ( - - - {this.state.setExp == 'by-days' && ( - - - - - {gettext('days')} - - - {!this.state.isExpireDaysNoLimit && ( - {this.expirationLimitTip} - )} - - )} - - - - {this.state.setExp == 'by-date' && ( - - )} - - {' '} - + +
+ + +
} @@ -562,15 +508,15 @@ class GenerateShareLink extends React.Component {
{shareLinkForceUsePassword ? ( - + ) : ( - + )} {this.state.isShowPasswordInput &&
@@ -603,39 +549,17 @@ class GenerateShareLink extends React.Component { {this.state.isExpireChecked &&
- - - {this.state.setExp == 'by-days' && ( - - - - - {gettext('days')} - - - {!this.state.isExpireDaysNoLimit && ( - {this.expirationLimitTip} - )} - - )} - - - - {this.state.setExp == 'by-date' && ( - - )} - +
} diff --git a/frontend/src/components/dialog/generate-upload-link.js b/frontend/src/components/dialog/generate-upload-link.js index 96d6cac1bb..f6ec12affc 100644 --- a/frontend/src/components/dialog/generate-upload-link.js +++ b/frontend/src/components/dialog/generate-upload-link.js @@ -1,16 +1,16 @@ -import React, { Fragment } from 'react'; +import React 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, FormText } from 'reactstrap'; +import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, Alert } from 'reactstrap'; import { gettext, shareLinkForceUsePassword, shareLinkPasswordMinLength, shareLinkPasswordStrengthLevel, canSendShareLinkEmail, uploadLinkExpireDaysMin, uploadLinkExpireDaysMax, uploadLinkExpireDaysDefault } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; import { Utils } from '../../utils/utils'; import UploadLink from '../../models/upload-link'; import toaster from '../toast'; import SendLink from '../send-link'; -import DateTimePicker from '../date-and-time-picker'; import SharedLink from '../shared-link'; +import SetLinkExpiration from '../set-link-expiration'; const propTypes = { itemPath: PropTypes.string.isRequired, @@ -27,20 +27,6 @@ class GenerateUploadLink extends React.Component { 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: shareLinkForceUsePassword ? true : false, passwordVisible: false, @@ -52,7 +38,7 @@ class GenerateUploadLink extends React.Component { isExpireChecked: !this.isExpireDaysNoLimit, isExpirationEditIconShow: false, isEditingExpiration: false, - setExp: 'by-days', + expType: 'by-days', expireDays: this.defaultExpireDays, expDate: null }; @@ -126,11 +112,11 @@ class GenerateUploadLink extends React.Component { this.setState({errorInfo: ''}); let { itemPath, repoID } = this.props; - let { password, isExpireChecked, setExp, expireDays, expDate } = this.state; + let { password, isExpireChecked, expType, expireDays, expDate } = this.state; let expirationTime = ''; if (isExpireChecked) { - if (setExp == 'by-days') { + if (expType == 'by-days') { expirationTime = moment().add(parseInt(expireDays), 'days').format(); } else { expirationTime = expDate.format(); @@ -148,7 +134,7 @@ class GenerateUploadLink extends React.Component { } validateParamsInput = () => { - let { showPasswordInput, password, passwordnew, isExpireChecked, setExp, expireDays, expDate } = this.state; + let { showPasswordInput, password, passwordnew, isExpireChecked, expType, expireDays, expDate } = this.state; // check password params if (showPasswordInput) { @@ -171,7 +157,7 @@ class GenerateUploadLink extends React.Component { } if (isExpireChecked) { - if (setExp == 'by-date') { + if (expType == 'by-date') { if (!expDate) { this.setState({errorInfo: gettext('Please select an expiration time')}); return false; @@ -197,33 +183,12 @@ class GenerateUploadLink extends React.Component { this.setState({isExpireChecked: e.target.checked}); } - setExp = (e) => { + setExpType = (e) => { this.setState({ - setExp: e.target.value + expType: e.target.value }); } - disabledDate = (current) => { - if (!current) { - // allow empty select - return false; - } - - 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) => { this.setState({ expDate: value @@ -259,10 +224,10 @@ class GenerateUploadLink extends React.Component { e.preventDefault(); e.nativeEvent.stopImmediatePropagation(); - let { setExp, expireDays, expDate } = this.state; + let { expType, expireDays, expDate } = this.state; let expirationTime = ''; - if (setExp == 'by-days') { + if (expType == 'by-days') { expirationTime = moment().add(parseInt(expireDays), 'days').format(); } else { expirationTime = expDate.format(); @@ -271,8 +236,8 @@ class GenerateUploadLink extends React.Component { seafileAPI.updateUploadLink(this.state.sharedUploadInfo.token, expirationTime).then((res) => { let sharedUploadInfo = new UploadLink(res.data); this.setState({ - sharedUploadInfo: sharedUploadInfo, - isEditingExpiration: false, + sharedUploadInfo: sharedUploadInfo, + isEditingExpiration: false, }); }).catch((error) => { let errMessage = Utils.getErrorMsg(error); @@ -286,6 +251,7 @@ class GenerateUploadLink extends React.Component { this.setState({ showPasswordInput: shareLinkForceUsePassword ? true : false, expireDays: this.defaultExpireDays, + expDate: null, isExpireChecked: !this.isExpireDaysNoLimit, password: '', passwordnew: '', @@ -309,7 +275,7 @@ class GenerateUploadLink extends React.Component { let passwordLengthTip = gettext('(at least {passwordMinLength} characters and includes {passwordStrengthLevel} of the following: number, upper letter, lower letter and other symbols)'); passwordLengthTip = passwordLengthTip.replace('{passwordMinLength}', shareLinkPasswordMinLength) - .replace('{passwordStrengthLevel}', shareLinkPasswordStrengthLevel); + .replace('{passwordStrengthLevel}', shareLinkPasswordStrengthLevel); if (this.state.sharedUploadInfo) { let sharedUploadInfo = this.state.sharedUploadInfo; @@ -344,7 +310,7 @@ class GenerateUploadLink extends React.Component {
{gettext('Expiration Date:')}
{!this.state.isEditingExpiration &&
- {moment(sharedUploadInfo.expire_date).format('YYYY-MM-DD HH:mm:ss')} + {moment(sharedUploadInfo.expire_date).format('YYYY-MM-DD HH:mm:ss')} {this.state.isExpirationEditIconShow && ( - - - {this.state.setExp == 'by-days' && ( - - - - - {gettext('days')} - - - {!this.state.isExpireDaysNoLimit && ( - {this.expirationLimitTip} - )} - - )} - - - - {this.state.setExp == 'by-date' && ( - - )} - - {' '} - + +
+ + +
} @@ -416,15 +362,15 @@ class GenerateUploadLink extends React.Component { {this.state.showPasswordInput && @@ -458,39 +404,17 @@ class GenerateUploadLink extends React.Component { {this.state.isExpireChecked &&
- - - {this.state.setExp == 'by-days' && ( - - - - - {gettext('days')} - - - {!this.state.isExpireDaysNoLimit && ( - {this.expirationLimitTip} - )} - - )} - - - - {this.state.setExp == 'by-date' && ( - - )} - +
}
diff --git a/frontend/src/components/set-link-expiration.js b/frontend/src/components/set-link-expiration.js new file mode 100644 index 0000000000..08d8d9ec33 --- /dev/null +++ b/frontend/src/components/set-link-expiration.js @@ -0,0 +1,119 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import moment from 'moment'; +import { FormGroup, Label, Input, InputGroup, InputGroupAddon, InputGroupText, FormText } from 'reactstrap'; +import { gettext } from '../utils/constants'; +import { Utils } from '../utils/utils'; +import DateTimePicker from './date-and-time-picker'; + +const propTypes = { + minDays: PropTypes.number.isRequired, + maxDays: PropTypes.number.isRequired, + defaultDays: PropTypes.number.isRequired, + expType: PropTypes.string.isRequired, + setExpType: PropTypes.func.isRequired, + expireDays: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number + ]), + onExpireDaysChanged: PropTypes.func.isRequired, + expDate: PropTypes.object, + onExpDateChanged: PropTypes.func.isRequired +}; + +const inputWidth = Utils.isDesktop() ? 250 : 210; + +class SetLinkExpiration extends React.Component { + + constructor(props) { + super(props); + + const { minDays, maxDays, defaultDays } = this.props; + this.isExpireDaysNoLimit = (minDays === 0 && maxDays === 0 && defaultDays == 0); + + let expirationLimitTip = ''; + if (minDays !== 0 && maxDays !== 0) { + expirationLimitTip = gettext('{minDays_placeholder} - {maxDays_placeholder} days') + .replace('{minDays_placeholder}', minDays) + .replace('{maxDays_placeholder}', maxDays); + } else if (minDays !== 0 && maxDays === 0) { + expirationLimitTip = gettext('Greater than or equal to {minDays_placeholder} days') + .replace('{minDays_placeholder}', minDays); + } else if (minDays === 0 && maxDays !== 0) { + expirationLimitTip = gettext('Less than or equal to {maxDays_placeholder} days') + .replace('{maxDays_placeholder}', maxDays); + } + this.expirationLimitTip = expirationLimitTip; + } + + disabledDate = (current) => { + if (!current) { + // allow empty select + return false; + } + + if (this.isExpireDaysNoLimit) { + return current.isBefore(moment(), 'day'); + } + + const { minDays, maxDays } = this.props; + const startDay = moment().add(minDays, 'days'); + const endDay = moment().add(maxDays, 'days'); + if (minDays !== 0 && maxDays !== 0) { + return current.isBefore(startDay, 'day') || current.isAfter(endDay, 'day'); + } else if (minDays !== 0 && maxDays === 0) { + return current.isBefore(startDay, 'day'); + } else if (minDays === 0 && maxDays !== 0) { + return current.isBefore(moment(), 'day') || current.isAfter(endDay, 'day'); + } + } + + render() { + const { + expType, setExpType, + expireDays, onExpireDaysChanged, + expDate, onExpDateChanged + } = this.props; + return ( + + + + {expType == 'by-days' && ( + + + + + {gettext('days')} + + + {!this.isExpireDaysNoLimit && ( + {this.expirationLimitTip} + )} + + )} + + + + {expType == 'by-date' && ( + + )} + + + ); + } +} + +SetLinkExpiration.propTypes = propTypes; + +export default SetLinkExpiration; diff --git a/seahub/api2/endpoints/share_links.py b/seahub/api2/endpoints/share_links.py index 7178d4a281..4dcde26a95 100644 --- a/seahub/api2/endpoints/share_links.py +++ b/seahub/api2/endpoints/share_links.py @@ -499,7 +499,7 @@ class ShareLink(APIView): try: perm = check_permissions_arg(request) except Exception: - error_msg = 'permissions invalud.' + error_msg = 'permissions invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if repo_folder_permission in (PERMISSION_PREVIEW_EDIT, PERMISSION_PREVIEW) \