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, 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 SharedLink from '../shared-link'; import SetLinkExpiration from '../set-link-expiration'; const propTypes = { itemPath: PropTypes.string.isRequired, repoID: PropTypes.string.isRequired, closeShareDialog: PropTypes.func.isRequired, }; 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; this.state = { showPasswordInput: shareLinkForceUsePassword ? true : false, passwordVisible: false, password: '', passwordnew: '', storedPasswordVisible: false, sharedUploadInfo: null, isSendLinkShown: false, isExpireChecked: !this.isExpireDaysNoLimit, isExpirationEditIconShow: false, isEditingExpiration: false, expType: 'by-days', expireDays: this.defaultExpireDays, expDate: null }; } componentDidMount() { this.getUploadLink(); } getUploadLink = () => { let path = this.props.itemPath; let repoID = this.props.repoID; seafileAPI.getUploadLink(repoID, path).then((res) => { if (res.data.length !== 0) { let sharedUploadInfo = new UploadLink(res.data[0]); this.setState({sharedUploadInfo: sharedUploadInfo}); } }).catch((err) => { let errMsg = Utils.getErrorMsg(err, true); if (!err.response || err.response.status !== 403) { toaster.danger(errMsg); } this.props.closeShareDialog(); }); }; addPassword = () => { this.setState({ showPasswordInput: !this.state.showPasswordInput, password: '', passwordnew: '', errorInfo: '' }); }; togglePasswordVisible = () => { this.setState({ passwordVisible: !this.state.passwordVisible }); }; generatePassword = () => { let val = Utils.generatePassword(shareLinkPasswordMinLength); this.setState({ password: val, passwordnew: val }); }; inputPassword = (e) => { this.setState({ password: e.target.value }); }; inputPasswordNew = (e) => { this.setState({ passwordnew: e.target.value }); }; toggleStoredPasswordVisible = () => { this.setState({ storedPasswordVisible: !this.state.storedPasswordVisible }); }; generateUploadLink = () => { let isValid = this.validateParamsInput(); if (isValid) { this.setState({errorInfo: ''}); let { itemPath, repoID } = this.props; let { password, isExpireChecked, expType, expireDays, expDate } = this.state; let expirationTime = ''; if (isExpireChecked) { if (expType == 'by-days') { expirationTime = moment().add(parseInt(expireDays), 'days').format(); } else { expirationTime = expDate.format(); } } seafileAPI.createUploadLink(repoID, itemPath, password, expirationTime).then((res) => { let sharedUploadInfo = new UploadLink(res.data); this.setState({sharedUploadInfo: sharedUploadInfo}); }).catch(error => { let errMessage = Utils.getErrorMsg(error); toaster.danger(errMessage); }); } }; validateParamsInput = () => { let { showPasswordInput, password, passwordnew, isExpireChecked, expType, expireDays, expDate } = this.state; // check password params if (showPasswordInput) { if (password.length === 0) { this.setState({errorInfo: gettext('Please enter a password.')}); return false; } if (password.length < shareLinkPasswordMinLength) { this.setState({errorInfo: gettext('The password is too short.')}); return false; } if (password !== passwordnew) { this.setState({errorInfo: gettext('Passwords don\'t match')}); return false; } if (Utils.getStrengthLevel(password) < shareLinkPasswordStrengthLevel) { this.setState({errorInfo: gettext('The password is too weak. It should include at least {passwordStrengthLevel} of the following: number, upper letter, lower letter and other symbols.').replace('{passwordStrengthLevel}', shareLinkPasswordStrengthLevel)}); return false; } } if (isExpireChecked) { if (expType == 'by-date') { if (!expDate) { this.setState({errorInfo: gettext('Please select an expiration time')}); return false; } return true; } let reg = /^\d+$/; if (!expireDays) { this.setState({errorInfo: gettext('Please enter days')}); return false; } if (!reg.test(expireDays)) { this.setState({errorInfo: gettext('Please enter a non-negative integer')}); return false; } this.setState({expireDays: parseInt(expireDays)}); } return true; }; onExpireChecked = (e) => { this.setState({isExpireChecked: e.target.checked}); }; setExpType = (e) => { this.setState({ expType: e.target.value }); }; onExpDateChanged = (value) => { this.setState({ expDate: value }); }; onExpireDaysChanged = (e) => { let day = e.target.value.trim(); this.setState({expireDays: day}); }; onCopyUploadLink = () => { let uploadLink = this.state.sharedUploadInfo.link; copy(uploadLink); toaster.success(gettext('Upload link is copied to the clipboard.')); 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 { expType, expireDays, expDate } = this.state; let expirationTime = ''; if (expType == '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, }); }).catch((error) => { let errMessage = Utils.getErrorMsg(error); toaster.danger(errMessage); }); }; deleteUploadLink = () => { let sharedUploadInfo = this.state.sharedUploadInfo; seafileAPI.deleteUploadLink(sharedUploadInfo.token).then(() => { this.setState({ showPasswordInput: shareLinkForceUsePassword ? true : false, expireDays: this.defaultExpireDays, expDate: null, isExpireChecked: !this.isExpireDaysNoLimit, password: '', passwordnew: '', sharedUploadInfo: null, }); }).catch(error => { let errMessage = Utils.getErrorMsg(error); toaster.danger(errMessage); }); }; toggleSendLink = () => { this.setState({ isSendLinkShown: !this.state.isSendLinkShown }); }; render() { const { isSendLinkShown } = this.state; 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); if (this.state.sharedUploadInfo) { let sharedUploadInfo = this.state.sharedUploadInfo; return (
{gettext('Upload Link:')}
{sharedUploadInfo.password && (
{gettext('Password:')}
)} {sharedUploadInfo.expire_date && (
{gettext('Expiration Date:')}
{!this.state.isEditingExpiration &&
{moment(sharedUploadInfo.expire_date).format('YYYY-MM-DD HH:mm:ss')} {this.state.isExpirationEditIconShow && ( )}
} {this.state.isEditingExpiration &&
}
)}
{canSendShareLinkEmail && !isSendLinkShown && } {!isSendLinkShown && } {isSendLinkShown && }
); } return (
{this.state.showPasswordInput &&
{passwordLengthTip}
}
{this.state.isExpireChecked &&
}
{this.state.errorInfo && {this.state.errorInfo}}
); } } GenerateUploadLink.propTypes = propTypes; export default GenerateUploadLink;