1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-01 23:20:51 +00:00

Merge branch '7.0'

This commit is contained in:
plt
2019-08-29 10:32:17 +08:00
8 changed files with 85 additions and 77 deletions

View File

@@ -24,6 +24,12 @@ class GenerateShareLink extends React.Component {
this.isExpireDaysNoLimit = (parseInt(shareLinkExpireDaysMin) === 0 && parseInt(shareLinkExpireDaysMax) === 0 && shareLinkExpireDaysDefault == 0); this.isExpireDaysNoLimit = (parseInt(shareLinkExpireDaysMin) === 0 && parseInt(shareLinkExpireDaysMax) === 0 && shareLinkExpireDaysDefault == 0);
this.defaultExpireDays = this.isExpireDaysNoLimit ? '' : shareLinkExpireDaysDefault; this.defaultExpireDays = this.isExpireDaysNoLimit ? '' : shareLinkExpireDaysDefault;
if (isPro) {
this.editOption = 'edit_download';
this.permissionOptions = ['preview_download', 'preview_only'];
}
this.state = { this.state = {
isValidate: false, isValidate: false,
isShowPasswordInput: false, isShowPasswordInput: false,
@@ -36,14 +42,9 @@ class GenerateShareLink extends React.Component {
sharedLinkInfo: null, sharedLinkInfo: null,
isNoticeMessageShow: false, isNoticeMessageShow: false,
isLoading: true, isLoading: true,
fileInfo: null, currentPermission: isPro ? this.permissionOptions[0] : '',
isSendLinkShown: false isSendLinkShown: false
}; };
this.permissions = {
'can_edit': false,
'can_download': true
};
this.isOfficeFile = Utils.isEditableOfficeFile(this.props.itemPath);
} }
componentDidMount() { componentDidMount() {
@@ -63,10 +64,11 @@ class GenerateShareLink extends React.Component {
let errMessage = Utils.getErrorMsg(error); let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage); toaster.danger(errMessage);
}); });
if (this.isOfficeFile) {
if (isPro && Utils.isEditableOfficeFile(path)) {
seafileAPI.getFileInfo(repoID, path).then((res) => { seafileAPI.getFileInfo(repoID, path).then((res) => {
if (res.data) { if (res.data.can_edit) {
this.setState({fileInfo: res.data}); this.permissionOptions.push(this.editOption);
} }
}).catch(error => { }).catch(error => {
let errMessage = Utils.getErrorMsg(error); let errMessage = Utils.getErrorMsg(error);
@@ -108,23 +110,8 @@ class GenerateShareLink extends React.Component {
this.setState({passwdnew: passwd}); this.setState({passwdnew: passwd});
} }
setPermission = (permission) => { setPermission = (e) => {
if (permission == 'previewAndDownload') { this.setState({currentPermission: e.target.value});
this.permissions = {
'can_edit': false,
'can_download': true
};
} else if (permission == 'preview') {
this.permissions = {
'can_edit': false,
'can_download': false
};
} else if (permission == 'editOnCloudAndDownload'){
this.permissions = {
'can_edit': true,
'can_download': true
};
}
} }
generateShareLink = () => { generateShareLink = () => {
@@ -133,7 +120,11 @@ class GenerateShareLink extends React.Component {
this.setState({errorInfo: ''}); this.setState({errorInfo: ''});
let { itemPath, repoID } = this.props; let { itemPath, repoID } = this.props;
let { password, isExpireChecked, expireDays } = this.state; let { password, isExpireChecked, expireDays } = this.state;
let permissions = isPro ? JSON.stringify(this.permissions) : ''; let permissions;
if (isPro) {
const permissionDetails = Utils.getShareLinkPermissionObject(this.state.currentPermission).permissionDetails;
permissions = JSON.stringify(permissionDetails);
}
const expireDaysSent = isExpireChecked ? expireDays : ''; const expireDaysSent = isExpireChecked ? expireDays : '';
seafileAPI.createShareLink(repoID, itemPath, password, expireDaysSent, permissions).then((res) => { seafileAPI.createShareLink(repoID, itemPath, password, expireDaysSent, permissions).then((res) => {
let sharedLinkInfo = new ShareLink(res.data); let sharedLinkInfo = new ShareLink(res.data);
@@ -172,10 +163,6 @@ class GenerateShareLink extends React.Component {
sharedLinkInfo: null, sharedLinkInfo: null,
isNoticeMessageShow: false, isNoticeMessageShow: false,
}); });
this.permissions = {
'can_edit': false,
'can_download': true
};
}).catch((error) => { }).catch((error) => {
let errMessage = Utils.getErrorMsg(error); let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage); toaster.danger(errMessage);
@@ -340,7 +327,6 @@ class GenerateShareLink extends React.Component {
</div> </div>
); );
} else { } else {
let fileInfo = this.state.fileInfo;
return ( return (
<Form className="generate-share-link"> <Form className="generate-share-link">
<FormGroup check> <FormGroup check>
@@ -403,28 +389,21 @@ class GenerateShareLink extends React.Component {
)} )}
{isPro && ( {isPro && (
<Fragment> <Fragment>
<FormGroup check> <FormGroup check>
<Label check> <Label check>
<span>{' '}{gettext('Set permission')}</span> <span>{gettext('Set permission')}</span>
</Label> </Label>
</FormGroup> </FormGroup>
<FormGroup check className="permission"> {this.permissionOptions.map((item, index) => {
<Label className="form-check-label"> return (
<Input type="radio" name="radio1" defaultChecked={true} onChange={() => this.setPermission('previewAndDownload')}/>{' '}{gettext('Preview and download')} <FormGroup check className="permission" key={index}>
</Label> <Label className="form-check-label">
</FormGroup> <Input type="radio" name="permission" value={item} checked={this.state.currentPermission == item} onChange={this.setPermission} className="mr-1" />
<FormGroup check className="permission"> {Utils.getShareLinkPermissionObject(item).text}
<Label className="form-check-label"> </Label>
<Input type="radio" name="radio1" onChange={() => this.setPermission('preview')} />{' '}{gettext('Preview only')} </FormGroup>
</Label> );
</FormGroup> })}
{(this.isOfficeFile && fileInfo && fileInfo.can_edit) &&
<FormGroup check className="permission">
<Label className="form-check-label">
<Input type="radio" name="radio1" onChange={() => this.setPermission('editOnCloudAndDownload')} />{' '}{gettext('Edit on cloud and download')}
</Label>
</FormGroup>
}
</Fragment> </Fragment>
)} )}
{this.state.errorInfo && <Alert color="danger" className="mt-2">{gettext(this.state.errorInfo)}</Alert>} {this.state.errorInfo && <Alert color="danger" className="mt-2">{gettext(this.state.errorInfo)}</Alert>}

View File

@@ -249,12 +249,12 @@ class FolderItem extends React.Component {
}); });
} }
renderLink = (node) => { renderLink = ({ href, name, path }) => {
const className = node.path === this.props.currentPath ? 'wiki-nav-content wiki-nav-content-highlight' : 'wiki-nav-content'; const className = `wiki-nav-content ${path === this.props.currentPath ? 'wiki-nav-content-highlight' : ''}`;
if (node.href && node.name) { if (href && name) {
return <div className={className}><a href={node.href} data-path={node.path} onClick={this.toggleExpanded}>{node.name}</a></div>; return <div className={className}><a href={href} data-path={path} onClick={this.toggleExpanded} title={name}>{name}</a></div>;
} else if (node.name) { } else if (name) {
return <div className="wiki-nav-content"><span onClick={this.toggleExpanded}>{node.name}</span></div>; return <div className="wiki-nav-content"><span onClick={this.toggleExpanded} title={name}>{name}</span></div>;
} else { } else {
return null; return null;
} }

View File

@@ -54,7 +54,9 @@ class MainSideNav extends React.Component {
this.groupsHeight = (groupList.length + 1) * _this.listHeight; this.groupsHeight = (groupList.length + 1) * _this.listHeight;
_this.setState({ _this.setState({
groupItems: groupList groupItems: groupList.sort((a, b) => {
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
})
}); });
}).catch(error => { }).catch(error => {
let errMessage = Utils.getErrorMsg(error); let errMessage = Utils.getErrorMsg(error);

View File

@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { gettext } from '../../utils/constants'; import { gettext } from '../../utils/constants';
const { err, trafficOverLimit } = window.shared.pageOptions; const { err, trafficOverLimit, zipped, filePath } = window.shared.pageOptions;
const propTypes = { const propTypes = {
errorMsg: PropTypes.string errorMsg: PropTypes.string
@@ -21,7 +21,7 @@ class SharedFileViewTip extends React.Component {
<div className="file-view-tip"> <div className="file-view-tip">
{errorMsg} {errorMsg}
{!trafficOverLimit && {!trafficOverLimit &&
<a href="?dl=1" className="btn btn-secondary">{gettext('Download')}</a> <a href={`?${zipped ? 'p=' + encodeURIComponent(filePath) + '&' : ''}dl=1`} className="btn btn-secondary">{gettext('Download')}</a>
} }
</div> </div>
</div> </div>

View File

@@ -1,5 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { Utils } from '../../utils/utils'; import { Utils } from '../../utils/utils';
import { gettext } from '../../utils/constants'; import { gettext } from '../../utils/constants';
import ModalPortal from '../modal-portal'; import ModalPortal from '../modal-portal';
@@ -35,6 +36,7 @@ class DirOperationToolbar extends React.Component {
isCreateMenuShow: false, isCreateMenuShow: false,
isShareDialogShow: false, isShareDialogShow: false,
operationMenuStyle: '', operationMenuStyle: '',
isMobileOpMenuOpen: false
}; };
} }
@@ -46,6 +48,10 @@ class DirOperationToolbar extends React.Component {
document.removeEventListener('click', this.hideOperationMenu); document.removeEventListener('click', this.hideOperationMenu);
} }
toggleMobileOpMenu = () => {
this.setState({isMobileOpMenuOpen: !this.state.isMobileOpMenuOpen});
}
hideOperationMenu = () => { hideOperationMenu = () => {
this.setState({ this.setState({
isUploadMenuShow: false, isUploadMenuShow: false,
@@ -161,17 +167,34 @@ class DirOperationToolbar extends React.Component {
let itemType = path === '/' ? 'library' : 'dir'; let itemType = path === '/' ? 'library' : 'dir';
let itemName = path == '/' ? repoName : Utils.getFolderName(path); let itemName = path == '/' ? repoName : Utils.getFolderName(path);
const content = Utils.isDesktop() ? (
<Fragment>
{Utils.isSupportUploadFolder() ?
<button className="btn btn-secondary operation-item" title={gettext('Upload')} onClick={this.onUploadClick}>{gettext('Upload')}</button> :
<button className="btn btn-secondary operation-item" title={gettext('Upload')} onClick={this.onUploadFile}>{gettext('Upload')}</button>}
<button className="btn btn-secondary operation-item" title={gettext('New')} onClick={this.onCreateClick}>{gettext('New')}</button>
{this.props.showShareBtn &&
<button className="btn btn-secondary operation-item" title={gettext('Share')} onClick={this.onShareClick}>{gettext('Share')}</button>}
</Fragment>
) : (
<Dropdown isOpen={this.state.isMobileOpMenuOpen} toggle={this.toggleMobileOpMenu}>
<DropdownToggle
tag="span"
className="sf2-icon-plus mobile-toolbar-icon"
/>
<DropdownMenu>
<DropdownItem onClick={this.onUploadFile}>{gettext('Upload')}</DropdownItem>
<DropdownItem onClick={this.onCreateFolderToggle}>{gettext('New Folder')}</DropdownItem>
<DropdownItem onClick={this.onCreateFileToggle}>{gettext('New File')}</DropdownItem>
</DropdownMenu>
</Dropdown>
);
return ( return (
<Fragment> <Fragment>
<div className="operation"> <div className="operation">
{Utils.isSupportUploadFolder() ? {content}
<button className="btn btn-secondary operation-item" title={gettext('Upload')} onClick={this.onUploadClick}>{gettext('Upload')}</button> :
<button className="btn btn-secondary operation-item" title={gettext('Upload')} onClick={this.onUploadFile}>{gettext('Upload')}</button>
}
<button className="btn btn-secondary operation-item" title={gettext('New')} onClick={this.onCreateClick}>{gettext('New')}</button>
{this.props.showShareBtn &&
<button className="btn btn-secondary operation-item" title={gettext('Share')} onClick={this.onShareClick}>{gettext('Share')}</button>
}
</div> </div>
{this.state.isUploadMenuShow && ( {this.state.isUploadMenuShow && (
<ul className="menu dropdown-menu" style={this.state.operationMenuStyle}> <ul className="menu dropdown-menu" style={this.state.operationMenuStyle}>

View File

@@ -1,5 +1,6 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Utils } from '../../utils/utils';
import { gettext } from '../../utils/constants'; import { gettext } from '../../utils/constants';
import CommonToolbar from '../../components/toolbar/common-toolbar'; import CommonToolbar from '../../components/toolbar/common-toolbar';
import ViewModeToolbar from '../../components/toolbar/view-mode-toolbar'; import ViewModeToolbar from '../../components/toolbar/view-mode-toolbar';
@@ -123,7 +124,7 @@ class LibContentToolbar extends React.Component {
/> />
} }
</div> </div>
<ViewModeToolbar currentMode={this.props.currentMode} switchViewMode={this.props.switchViewMode}/> {Utils.isDesktop() && <ViewModeToolbar currentMode={this.props.currentMode} switchViewMode={this.props.switchViewMode} />}
</div> </div>
<CommonToolbar repoID={this.props.repoID} onSearchedClick={this.props.onSearchedClick} searchPlaceholder={gettext('Search files in this library')}/> <CommonToolbar repoID={this.props.repoID} onSearchedClick={this.props.onSearchedClick} searchPlaceholder={gettext('Search files in this library')}/>
</Fragment> </Fragment>

View File

@@ -2,7 +2,7 @@ import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import cookie from 'react-cookies'; import cookie from 'react-cookies';
import MediaQuery from 'react-responsive'; import MediaQuery from 'react-responsive';
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem} from 'reactstrap'; import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { seafileAPI } from '../../utils/seafile-api'; import { seafileAPI } from '../../utils/seafile-api';
import { gettext, loginUrl, canAddPublicRepo } from '../../utils/constants'; import { gettext, loginUrl, canAddPublicRepo } from '../../utils/constants';
import { Utils } from '../../utils/utils'; import { Utils } from '../../utils/utils';

View File

@@ -86,15 +86,18 @@ def _handle_login_form_valid(request, user, redirect_to, remember_me):
@csrf_protect @csrf_protect
@never_cache @never_cache
def login(request, template_name='registration/login.html', def login(request, template_name='registration/login.html',
redirect_if_logged_in=None, redirect_if_logged_in='libraries',
redirect_field_name=REDIRECT_FIELD_NAME, redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm): authentication_form=AuthenticationForm):
"""Displays the login form and handles the login action.""" """Displays the login form and handles the login action."""
if request.user.is_authenticated() and redirect_if_logged_in:
return HttpResponseRedirect(reverse(redirect_if_logged_in))
redirect_to = request.GET.get(redirect_field_name, '') redirect_to = request.GET.get(redirect_field_name, '')
if request.user.is_authenticated():
if redirect_to:
return HttpResponseRedirect(redirect_to)
else:
return HttpResponseRedirect(reverse(redirect_if_logged_in))
ip = get_remote_ip(request) ip = get_remote_ip(request)
if request.method == "POST": if request.method == "POST":