import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import moment from 'moment'; import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, Alert } from 'reactstrap'; import { gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax, shareLinkExpireDaysDefault, shareLinkForceUsePassword, shareLinkPasswordMinLength, shareLinkPasswordStrengthLevel, isEmailConfigured } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; import { shareLinkAPI } from '../../utils/share-link-api'; import { Utils } from '../../utils/utils'; import ShareLink from '../../models/share-link'; import toaster from '../toast'; import SetLinkExpiration from '../set-link-expiration'; import UserSelect from '../user-select'; const propTypes = { itemPath: PropTypes.string.isRequired, repoID: PropTypes.string.isRequired, userPerm: PropTypes.string, type: PropTypes.string.isRequired, permissionOptions: PropTypes.array.isRequired, currentPermission: PropTypes.string.isRequired, updateAfterCreation: PropTypes.func.isRequired, setMode: PropTypes.func.isRequired, }; const inputWidth = Utils.isDesktop() ? 250 : 210; const SHARE_LINK_MAX_NUMBER = 200; class LinkCreation extends React.Component { constructor(props) { super(props); this.isExpireDaysNoLimit = (shareLinkExpireDaysMin === 0 && shareLinkExpireDaysMax === 0 && shareLinkExpireDaysDefault == 0); this.defaultExpireDays = this.isExpireDaysNoLimit ? '' : shareLinkExpireDaysDefault; this.state = { linkAmount: '', isShowPasswordInput: shareLinkForceUsePassword ? true : false, isPasswordVisible: false, isExpireChecked: !this.isExpireDaysNoLimit, expType: 'by-days', expireDays: this.defaultExpireDays, expDate: null, password: '', passwdnew: '', errorInfo: '', currentPermission: props.currentPermission, currentScope: 'all_users', selectedOption: null, inputEmails: '' }; } setExpType = (e) => { this.setState({ expType: e.target.value }); }; onExpDateChanged = (value) => { this.setState({ expDate: value }); }; onPasswordInputChecked = () => { this.setState({ isShowPasswordInput: !this.state.isShowPasswordInput, password: '', passwdnew: '', errorInfo: '' }); }; togglePasswordVisible = () => { this.setState({ isPasswordVisible: !this.state.isPasswordVisible }); }; generatePassword = () => { let val = Utils.generatePassword(shareLinkPasswordMinLength); this.setState({ password: val, passwdnew: val }); }; inputPassword = (e) => { let passwd = e.target.value.trim(); this.setState({ password: passwd }); }; inputPasswordNew = (e) => { let passwd = e.target.value.trim(); this.setState({ passwdnew: passwd }); }; setPermission = (e) => { this.setState({ currentPermission: e.target.value }); }; generateShareLink = () => { let isValid = this.validateParamsInput(); if (isValid) { this.setState({ errorInfo: '' }); let { type, itemPath, repoID } = this.props; let { linkAmount, isShowPasswordInput, password, isExpireChecked, expType, expireDays, expDate } = this.state; const permissionDetails = Utils.getShareLinkPermissionObject(this.state.currentPermission).permissionDetails; let permissions; permissions = JSON.stringify(permissionDetails); let expirationTime = ''; if (isExpireChecked) { if (expType === 'by-days') { expirationTime = moment().add(parseInt(expireDays), 'days').format(); } else { expirationTime = expDate.format(); } } let request; let users; if (type === 'batch') { const autoGeneratePassword = shareLinkForceUsePassword || isShowPasswordInput; request = seafileAPI.batchCreateMultiShareLink(repoID, itemPath, linkAmount, autoGeneratePassword, expirationTime, permissions); } else { const { currentScope, selectedOption, inputEmails } = this.state; if (currentScope === 'specific_users' && selectedOption) { users = selectedOption.map((item, index) => item.email); } if (currentScope === 'specific_emails' && inputEmails) { users = inputEmails; } request = shareLinkAPI.createMultiShareLink(repoID, itemPath, password, expirationTime, permissions, currentScope, users); } request.then((res) => { if (type === 'batch') { const newLinks = res.data.map(item => new ShareLink(item)); this.props.updateAfterCreation(newLinks); } else { const newLink = new ShareLink(res.data); this.props.updateAfterCreation(newLink); } }).catch((error) => { let resp_data = error.response.data; let errMessage = resp_data && resp_data['error_msg']; if (errMessage === 'Folder permission denied.') { this.setState({ errorInfo: gettext('Share links cannot be generated because "Invisible", "Online Read-Write" or "Online Read-Only" is set for you on some folder(s) in the library.') }); } else { let errMessage = Utils.getErrorMsg(error); toaster.danger(errMessage); } }); } }; onExpireChecked = (e) => { this.setState({ isExpireChecked: e.target.checked }); }; onExpireDaysChanged = (e) => { let day = e.target.value.trim(); this.setState({ expireDays: day }); }; validateParamsInput = () => { const { type } = this.props; let { linkAmount, isShowPasswordInput, password, passwdnew, isExpireChecked, expType, expireDays, expDate } = this.state; if (type === 'batch') { if (!Number.isInteger(parseInt(linkAmount)) || parseInt(linkAmount) <= 1) { this.setState({ errorInfo: gettext('Please enter an integer bigger than 1 as number of links.') }); return false; } if (parseInt(linkAmount) > SHARE_LINK_MAX_NUMBER) { this.setState({ errorInfo: gettext('Please enter an integer not bigger than {max_number} as number of links.').replace('{max_number}', SHARE_LINK_MAX_NUMBER) }); return false; } } if (type === 'single' && isShowPasswordInput) { 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 !== passwdnew) { 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; } // by days 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; } expireDays = parseInt(expireDays); let minDays = shareLinkExpireDaysMin; let maxDays = shareLinkExpireDaysMax; if (minDays !== 0 && maxDays === 0) { if (expireDays < minDays) { this.setState({ errorInfo: 'Please enter valid days' }); return false; } } if (minDays === 0 && maxDays !== 0) { if (expireDays > maxDays) { this.setState({ errorInfo: 'Please enter valid days' }); return false; } } if (minDays !== 0 && maxDays !== 0) { if (expireDays < minDays || expireDays > maxDays) { this.setState({ errorInfo: 'Please enter valid days' }); return false; } } this.setState({ expireDays: expireDays }); } return true; }; onLinkAmountChange = (e) => { this.setState({ linkAmount: e.target.value }); }; goBack = () => { this.props.setMode(''); }; setScope = (e) => { this.setState({ currentScope: e.target.value, selectedOption: null, inputEmails: '' }); }; handleSelectChange = (option) => { this.setState({ selectedOption: option }); }; handleInputChange = (e) => { this.setState({ inputEmails: e.target.value }); }; render() { const { userPerm, type, permissionOptions } = this.props; const { isCustomPermission } = Utils.getUserPermission(userPerm); return (
{type === 'batch' ? gettext('Generate links in batch') : gettext('Generate Link')}
{type === 'batch' && ( )} {shareLinkForceUsePassword ? ( ) : ( )} {type !== 'batch' && this.state.isShowPasswordInput &&
{gettext('(at least {passwordMinLength} characters and includes {passwordStrengthLevel} of the following: number, upper letter, lower letter and other symbols)').replace('{passwordMinLength}', shareLinkPasswordMinLength).replace('{passwordStrengthLevel}', shareLinkPasswordStrengthLevel)}
}
{this.state.isExpireChecked &&
}
{!isCustomPermission && ( {permissionOptions.map((item, index) => { return ( ); })} )} {type !== 'batch' && ( {this.state.currentScope === 'specific_users' && } {isEmailConfigured && ( {this.state.currentScope === 'specific_emails' && } )} )} {this.state.errorInfo && {gettext(this.state.errorInfo)}}
); } } LinkCreation.propTypes = propTypes; export default LinkCreation;