1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-08 02:10:24 +00:00

Merge branch '7.0'

This commit is contained in:
lian
2019-06-27 18:39:55 +08:00
28 changed files with 229 additions and 144 deletions

View File

@@ -1,5 +1,6 @@
language: python
python: 2.7.12
python:
- "2.7"
cache:
directories:
@@ -10,24 +11,22 @@ before_cache:
env:
global:
- CCNET_CONF_DIR=/tmp/ccnet SEAFILE_CONF_DIR=/tmp/seafile-data
- secure: "AFqKit45l2758+TrH/l0SFN6k5lc9ALmZGPBGbGeYSzSGZ4+Cx7tHyQwgZgiitf9BzVci1ClaIMfNxp8BG6ECDAMXcbMyAksItG2aM/x//YT59ljgrwnNeZFfwh8LWuZslboxXx/Pfrv9QSX0c6dcTyEfKFLVKW1U2bn4MxdF+A="
- secure: "cXNbNl1wiIXk7D6jviQa4tg0XfAPPT/uze2dchniYZm/5clxiOXuLAfFqXrF+morakWv7+nZeoXh+RFMSllQvwJlGGRoD01hazoJTGhoV+7Be2KHTGG/YwUKT/PzxgRqPDNW3XUkPWChQQXjP+nb6QjbMrXcbNOgE+Glb23Gz0k="
# install & start seafile-server CE v6.3, install phantomjs & nginx
# install & start seafile-server CE, install nginx
before_install:
# npm token to fetch private repos
- echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" > ~/.npmrc
# build/init/start ccnet-server/seafile-server
- git clone --depth=1 --branch=7.0 git://github.com/haiwen/seafile-test-deploy /tmp/seafile-test-deploy
- git clone --depth=1 --branch=master git://github.com/haiwen/seafile-test-deploy /tmp/seafile-test-deploy
- cd /tmp/seafile-test-deploy && ./bootstrap.sh && cd -
# install phantomjs
# install nginx
- ./tests/install-deps.sh
- npm install -g requirejs
- openssl aes-256-cbc -K $encrypted_bdef00a70236_key -iv $encrypted_bdef00a70236_iv -in .travis/travis_deploy_key.enc -out travis_deploy_key -d && mv travis_deploy_key ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa
# install seahub requirements
install:
- pip install -r dev-requirements.txt --allow-all-external --allow-unverified PIL
- pip install -r dev-requirements.txt
- pip install -r test-requirements.txt
before_scipt: true
@@ -37,10 +36,7 @@ script: true
# - .travis/test_seahub_changes.sh; rc=$?; if [[ $rc == 0 ]]; then ./tests/seahubtests.sh init && ./tests/seahubtests.sh runserver && ./tests/seahubtests.sh test; else true; fi
after_success:
# notify seafile-docs to rebuild if master is updated
# - test $TRAVIS_PULL_REQUEST = "false" && test $TRAVIS_BRANCH = "master" && .travis/rebuild-branches.sh
# making dist assets if current branch(master/6.3/6.2) is updated
# making dist assets if current branch(master/7.0) is updated
- test $TRAVIS_PULL_REQUEST = "false" && .travis/dist_and_push.sh
after_failure: true
@@ -58,5 +54,3 @@ branches:
only:
- master
- 7.0
- seafile-docs
- master-tmp-lian

View File

@@ -17,11 +17,13 @@ set +x
function commit_dist_files() {
git checkout -b dist-$TRAVIS_BRANCH
git add -u . && git add -A media/assets && git add -A static/scripts && git add -A frontend && git add -A locale
git commit -m "[dist] Travis build: #$TRAVIS_BUILD_NUMBER, based on commit $TRAVIS_COMMIT." -m "https://travis-ci.org/haiwen/seahub/builds/$TRAVIS_BUILD_ID" -m "$TRAVIS_COMMIT_MESSAGE"
git commit -m "[dist] Travis build: #$TRAVIS_BUILD_NUMBER, based on commit $TRAVIS_COMMIT." -m "$TRAVIS_COMMIT_MESSAGE"
}
function upload_files() {
git push git@github.com:haiwen/seahub.git dist-$TRAVIS_BRANCH -f
echo 'push dist to seahub'
git remote add token-origin https://imwhatiam:${GITHUB_PERSONAL_ACCESS_TOKEN}@github.com/haiwen/seahub.git
git push -f token-origin dist-$TRAVIS_BRANCH
}
function make_dist() {

View File

@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Modal, ModalHeader, Input, ModalBody, ModalFooter, Form, FormGroup, Label, Alert } from 'reactstrap';
import { gettext, enableEncryptedLibrary } from '../../utils/constants';
import { gettext, enableEncryptedLibrary, repoPasswordMinLength } from '../../utils/constants';
const propTypes = {
libraryType: PropTypes.string.isRequired,
@@ -99,7 +99,7 @@ class CreateRepoDialog extends React.Component {
this.setState({errMessage: errMessage});
return false;
}
if (password1.length < 8) {
if (password1.length < repoPasswordMinLength) {
errMessage = gettext('Password is too short');
this.setState({errMessage: errMessage});
return false;
@@ -197,7 +197,7 @@ class CreateRepoDialog extends React.Component {
{!this.state.disabled &&
<FormGroup>
{/* todo translate */}
<Label for="passwd1" className="font-weight-bold">{gettext('Password')}</Label><span className="tip">{' '}{gettext('(at least 8 characters)')}</span>
<Label for="passwd1" className="font-weight-bold">{gettext('Password')}</Label><span className="tip">{' '}{gettext('(at least {placeholder} characters)').replace('{placeholder}', repoPasswordMinLength)}</span>
<Input
id="passwd1"
type="password"

View File

@@ -3,12 +3,13 @@ import PropTypes from 'prop-types';
import moment from 'moment';
import copy from 'copy-to-clipboard';
import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, Alert } from 'reactstrap';
import { gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax, shareLinkExpireDaysDefault, shareLinkPasswordMinLength } from '../../utils/constants';
import { gettext, shareLinkExpireDaysMin, shareLinkExpireDaysMax, shareLinkExpireDaysDefault, shareLinkPasswordMinLength, canSendShareLinkEmail } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import SharedLinkInfo from '../../models/shared-link-info';
import toaster from '../toast';
import Loading from '../loading';
import SendLink from '../send-link';
const propTypes = {
itemPath: PropTypes.string.isRequired,
@@ -32,11 +33,8 @@ class GenerateShareLink extends React.Component {
sharedLinkInfo: null,
isNoticeMessageShow: false,
isLoading: true,
isShowSendLink: false,
sendLinkEmails: '',
sendLinkMessage: '',
sendLinkErrorMessage: '',
fileInfo: null,
isSendLinkShown: false
};
this.permissions = {
'can_edit': false,
@@ -254,45 +252,8 @@ class GenerateShareLink extends React.Component {
this.setState({isNoticeMessageShow: !this.state.isNoticeMessageShow});
}
onSendLinkEmailsChange = (event) => {
if (this.state.sendLinkErrorMessage) this.setState({ sendLinkErrorMessage: '' });
this.setState({sendLinkEmails: event.target.value});
}
onSendLinkMessageChange = (event) => {
if (this.state.sendLinkErrorMessage) this.setState({ sendLinkErrorMessage: '' });
this.setState({sendLinkMessage: event.target.value});
}
toggleSendLink = () => {
this.setState({ isShowSendLink: !this.state.isShowSendLink });
}
sendShareLink = () => {
if (!this.state.sendLinkEmails) return;
const token = this.state.sharedLinkInfo.token;
const emails = this.state.sendLinkEmails.replace(/\s*/g,'');
const message = this.state.sendLinkMessage.trim();
this.setState({ isLoading: true });
seafileAPI.sendShareLink(token, emails, message).then((res) => {
this.props.closeShareDialog();
if (res.data.failed.length > 0) {
res.data.failed.map(failed => {
toaster.warning(gettext('Failed sent link to') + ' ' + failed.email + ', ' + failed.error_msg);
});
}
if (res.data.success.length > 0) {
let users = res.data.success.join(',');
toaster.success(gettext('Successfully sent link to') + ' ' + users);
}
}).catch((error) => {
if (error.response) {
this.setState({
sendLinkErrorMessage: error.response.data.error_msg,
isLoading: false,
});
}
});
this.setState({ isSendLinkShown: !this.state.isSendLinkShown });
}
render() {
@@ -338,38 +299,18 @@ class GenerateShareLink extends React.Component {
</FormGroup>
)}
</Form>
{(!this.state.isShowSendLink && !this.state.isNoticeMessageShow) &&
{(canSendShareLinkEmail && !this.state.isSendLinkShown && !this.state.isNoticeMessageShow) &&
<Button onClick={this.toggleSendLink} className='mr-2'>{gettext('Send')}</Button>
}
{this.state.isShowSendLink &&
<Fragment>
<Form>
<FormGroup>
<Label htmlFor="sendLinkEmails" className="text-secondary font-weight-normal">{gettext('Send to')}{':'}</Label>
<Input
id="sendLinkEmails"
className="w-75"
value={this.state.sendLinkEmails}
onChange={this.onSendLinkEmailsChange}
placeholder={gettext('Emails, separated by \',\'')}
{this.state.isSendLinkShown &&
<SendLink
linkType='shareLink'
token={sharedLinkInfo.token}
toggleSendLink={this.toggleSendLink}
closeShareDialog={this.props.closeShareDialog}
/>
</FormGroup>
<FormGroup>
<Label htmlFor="sendLinkMessage" className="text-secondary font-weight-normal">{gettext('Message (optional):')}</Label><br/>
<textarea
className="w-75"
id="sendLinkMessage"
value={this.state.sendLinkMessage}
onChange={this.onSendLinkMessageChange}
></textarea>
</FormGroup>
</Form>
{this.state.sendLinkErrorMessage && <p className="error">{this.state.sendLinkErrorMessage}</p>}
<Button color="primary" onClick={this.sendShareLink}>{gettext('Send')}</Button>{' '}
<Button color="secondary" onClick={this.toggleSendLink}>{gettext('Cancel')}</Button>{' '}
</Fragment>
}
{(!this.state.isShowSendLink && !this.state.isNoticeMessageShow) &&
{(!this.state.isSendLinkShown && !this.state.isNoticeMessageShow) &&
<Button onClick={this.onNoticeMessageToggle}>{gettext('Delete')}</Button>
}
{this.state.isNoticeMessageShow &&

View File

@@ -2,11 +2,12 @@ import React from 'react';
import PropTypes from 'prop-types';
import copy from 'copy-to-clipboard';
import { Button, Form, FormGroup, Label, Input, InputGroup, InputGroupAddon, Alert } from 'reactstrap';
import { gettext, shareLinkPasswordMinLength } from '../../utils/constants';
import { gettext, shareLinkPasswordMinLength, canSendShareLinkEmail } from '../../utils/constants';
import { seafileAPI } from '../../utils/seafile-api';
import { Utils } from '../../utils/utils';
import SharedUploadInfo from '../../models/shared-upload-info';
import toaster from '../toast';
import SendLink from '../send-link';
import SessionExpiredTip from '../session-expired-tip';
const propTypes = {
@@ -24,6 +25,7 @@ class GenerateUploadLink extends React.Component {
password: '',
passwdnew: '',
sharedUploadInfo: null,
isSendLinkShown: false
};
}
@@ -130,8 +132,16 @@ class GenerateUploadLink extends React.Component {
});
}
toggleSendLink = () => {
this.setState({
isSendLinkShown: !this.state.isSendLinkShown
});
}
render() {
const { isSendLinkShown } = this.state;
let passwordLengthTip = gettext('(at least {passwordLength} characters)');
passwordLengthTip = passwordLengthTip.replace('{passwordLength}', shareLinkPasswordMinLength);
if (this.state.sharedUploadInfo) {
@@ -147,7 +157,16 @@ class GenerateUploadLink extends React.Component {
</dd>
</FormGroup>
</Form>
<Button onClick={this.deleteUploadLink}>{gettext('Delete')}</Button>
{canSendShareLinkEmail && !isSendLinkShown && <Button onClick={this.toggleSendLink} className="mr-2">{gettext('Send')}</Button>}
{!isSendLinkShown && <Button onClick={this.deleteUploadLink}>{gettext('Delete')}</Button>}
{isSendLinkShown &&
<SendLink
linkType='uploadLink'
token={sharedUploadInfo.token}
toggleSendLink={this.toggleSendLink}
closeShareDialog={this.props.closeShareDialog}
/>
}
</div>
);
}

View File

@@ -87,13 +87,14 @@ class LabelRepoStateDialog extends React.Component {
render() {
return (
<Modal isOpen={true} centered={true} toggle={this.props.toggleDialog}>
<ModalHeader toggle={this.props.toggleDialog}>{gettext('Label current state')}</ModalHeader>
<Modal isOpen={true} toggle={this.props.toggleDialog}>
<ModalHeader toggle={this.props.toggleDialog}>{gettext('Label Current State')}</ModalHeader>
<ModalBody>
<Content data={this.state} handleChange={this.handleInputChange} />
</ModalBody>
{this.state.existingLabels && (
<ModalFooter>
<button className="btn btn-secondary" onClick={this.props.toggleDialog}>{gettext('Cancel')}</button>
<button className="btn btn-primary" disabled={this.state.submitBtnDisabled} onClick={this.formSubmit}>{gettext('Submit')}</button>
</ModalFooter>
)}

View File

@@ -94,7 +94,7 @@ class LibHistorySetting extends React.Component {
render() {
const itemName = this.props.itemName;
return (
<Modal isOpen={true} centered={true}>
<Modal isOpen={true}>
<ModalHeader toggle={this.props.toggleDialog}>
<span className="op-target" title={itemName}>{itemName}</span>{' '}
{gettext('History Setting')}

View File

@@ -0,0 +1,128 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Form, FormGroup, Label } from 'reactstrap';
import { seafileAPI } from '../utils/seafile-api';
import { gettext } from '../utils/constants';
import toaster from './toast';
const propTypes = {
token: PropTypes.string.isRequired,
linkType: PropTypes.string.isRequired,
toggleSendLink: PropTypes.func.isRequired,
closeShareDialog: PropTypes.func.isRequired
};
class SendLink extends React.Component {
constructor(props) {
super(props);
this.state = {
emails: '',
msg: '',
errorMsg: '',
btnDisabled: false,
sending: false
};
}
handleEmailsInputChange = (e) => {
this.setState({
emails: e.target.value
});
}
handleMsgInputChange = (e) => {
this.setState({
msg: e.target.value
});
}
sendLink = () => {
const { emails, msg } = this.state;
if (!emails.trim()) {
this.setState({
errorMsg: gettext('Please input at least an email.')
});
return;
}
this.setState({
btnDisabled: true,
sending: true
});
const { token, linkType } = this.props;
const request = linkType == 'uploadLink' ?
seafileAPI.sendUploadLink(token, emails.trim(), msg.trim()) :
seafileAPI.sendShareLink(token, emails.trim(), msg.trim());
request.then((res) => {
this.props.closeShareDialog();
const { success, failed } = res.data;
if (success.length) {
const feedbackMsg = gettext('Successfully sent to {placeholder}')
.replace('{placeholder}', success.join(', '));
toaster.success(feedbackMsg);
}
if (failed.length) {
failed.map((item) => {
const feedbackMsg = gettext('Failed to send to {email_placeholder}: {errorMsg_placeholder}')
.replace('{email_placeholder}', item.email)
.replace('{errorMsg_placeholder}', item.error_msg);
toaster.warning(feedbackMsg);
});
}
}).catch((error) => {
let errorMsg = '';
if (error.response) {
if (error.response.data && error.response.data['error_msg']) {
errorMsg = error.response.data['error_msg'];
} else {
errorMsg = gettext('Error');
}
} else {
errorMsg = gettext('Please check the network.');
}
this.setState({
btnDisabled: false,
sending: false,
errorMsg: errorMsg
});
});
}
render() {
const { emails, msg, errorMsg, btnDisabled, sending } = this.state;
return (
<Form>
<FormGroup>
<Label htmlFor="emails" className="text-secondary font-weight-normal">{gettext('Send to:')}</Label>
<input
type="text"
id="emails"
className="form-control w-75"
value={emails}
onChange={this.handleEmailsInputChange}
placeholder={gettext('Emails, separated by \',\'')}
/>
</FormGroup>
<FormGroup>
<Label htmlFor="msg" className="text-secondary font-weight-normal">{gettext('Message (optional):')}</Label>
<textarea
className="form-control w-75"
id="msg"
value={msg}
onChange={this.handleMsgInputChange}
></textarea>
</FormGroup>
{errorMsg && <p className="error">{errorMsg}</p>}
<Button color="primary" onClick={this.sendLink} disabled={btnDisabled} className="mr-2">{gettext('Send')}</Button>
<Button color="secondary" onClick={this.props.toggleSendLink}>{gettext('Cancel')}</Button>
{sending && <p className="mt-2">{gettext('Sending...')}</p>}
</Form>
);
}
}
SendLink.propTypes = propTypes;
export default SendLink;

View File

@@ -277,11 +277,11 @@ class SharedRepoListItem extends React.Component {
if (this.props.libraryType && this.props.libraryType === 'public') {
let isRepoOwner = this.props.repo.owner_email === username;
if (isSystemStaff || isRepoOwner) {
operations.push('unshare');
operations.push('Unshare');
}
} else {
// scene one: (share, delete, itemToggle and other operations);
// scene two: (share, unshare), (share), (unshare)
// scene one: (Share, Delete, itemToggle and other operations);
// scene two: (Share, Unshare), (Share), (Unshare)
operations = this.generatorOperations();
}
const shareOperation = <a href="#" className="op-icon sf2-icon-share" title={gettext('Share')} onClick={this.onItemShare}></a>;
@@ -319,11 +319,11 @@ class SharedRepoListItem extends React.Component {
</Fragment>
);
}
if (operations.length == 1 && operations[0] === 'share') {
if (operations.length == 1 && operations[0] === 'Share') {
return shareOperation;
}
if (operations.length == 1 && operations[0] === 'unshare') {
if (operations.length == 1 && operations[0] === 'Unshare') {
return unshareOperation;
}
}

View File

@@ -1484,7 +1484,11 @@ class LibContentView extends React.Component {
let { currentRepoInfo, userPerm } = this.state;
let showShareBtn = Utils.isHasPermissionToShare(currentRepoInfo, userPerm);
let isRepoOwner = currentRepoInfo.owner_email === username;
let isVirtual = currentRepoInfo.is_virtual;
let isAdmin = currentRepoInfo.is_admin;
if (!isVirtual && (isRepoOwner || isAdmin)) {
enableDirPrivateShare = true;
}
let direntItemsList = this.state.direntList.filter((item, index) => {
return index < this.state.itemsShowLength;
});

View File

@@ -93,7 +93,7 @@ class MylibRepoListItem extends React.Component {
case 'Folder Permission':
this.onFolderPermissionToggle();
break;
case 'Label current state':
case 'Label Current State':
this.onLabelToggle();
break;
default:

View File

@@ -63,7 +63,7 @@ class MylibRepoMenu extends React.Component {
operations.push('Folder Permission');
}
if (this.props.isPC && enableRepoSnapshotLabel) {
operations.push('Label current state');
operations.push('Label Current State');
}
return operations;
}
@@ -95,8 +95,8 @@ class MylibRepoMenu extends React.Component {
case 'Folder Permission':
translateResult = gettext('Folder Permission');
break;
case 'Label current state':
translateResult = gettext('Label current state');
case 'Label Current State':
translateResult = gettext('Label Current State');
break;
default:
break;

View File

@@ -25,7 +25,8 @@ export const username = window.app.pageOptions.username;
export const canAddRepo = window.app.pageOptions.canAddRepo;
export const canAddGroup = window.app.pageOptions.canAddGroup;
export const canGenerateShareLink = window.app.pageOptions.canGenerateShareLink;
export const canGenerateUploadLink = window.app.pageOptions.canGenerateUploadLink ? true : false;
export const canGenerateUploadLink = window.app.pageOptions.canGenerateUploadLink;
export const canSendShareLinkEmail = window.app.pageOptions.canSendShareLinkEmail;
export const canViewOrg = window.app.pageOptions.canViewOrg === 'True';
export const fileAuditEnabled = window.app.pageOptions.fileAuditEnabled;
export const enableFileComment = window.app.pageOptions.enableFileComment ? true : false;

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -117,7 +117,7 @@ class AdminGroups(APIView):
group_name = group_name.strip()
# Check whether group name is validate.
if not validate_group_name(group_name):
error_msg = _(u'Group name can only contain letters, numbers, blank, hyphen, period, single quote or underscore')
error_msg = _(u'Group name can only contain letters, numbers, blank, hyphen, dot, single quote or underscore')
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# Check whether group name is duplicated.

View File

@@ -202,7 +202,7 @@ class Groups(APIView):
# Check whether group name is validate.
if not validate_group_name(group_name):
error_msg = _(u'Group name can only contain letters, numbers, blank, hyphen, period, single quote or underscore')
error_msg = _(u'Group name can only contain letters, numbers, blank, hyphen, dot, single quote or underscore')
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# Check whether group name is duplicated.

View File

@@ -70,7 +70,7 @@ class SendUploadLinkView(APIView):
if not is_valid_email(to_email):
failed_info['email'] = to_email
failed_info['error_msg'] = 'email invalid.'
failed_info['error_msg'] = _(u'email invalid.')
result['failed'].append(failed_info)
continue
@@ -102,7 +102,7 @@ class SendUploadLinkView(APIView):
except Exception as e:
logger.error(e)
failed_info['email'] = to_email
failed_info['error_msg'] = 'Internal Server Error'
failed_info['error_msg'] = _(u'Internal Server Error')
result['failed'].append(failed_info)
return Response(result)

View File

@@ -244,11 +244,11 @@ def logout(request, next_page=None,
shib_logout_return = getattr(settings, 'SHIBBOLETH_LOGOUT_RETURN', '')
if shib_logout_return:
shib_logout_url += shib_logout_return
return HttpResponseRedirect(shib_logout_url)
response = HttpResponseRedirect(shib_logout_url)
# Local logout for cas user.
if getattr(settings, 'ENABLE_CAS', False):
return HttpResponseRedirect(reverse('cas_ng_logout'))
response = HttpResponseRedirect(reverse('cas_ng_logout'))
if redirect_field_name in request.GET:
next_page = request.GET[redirect_field_name]
@@ -259,14 +259,17 @@ def logout(request, next_page=None,
if next_page is None:
redirect_to = request.GET.get(redirect_field_name, '')
if redirect_to:
return HttpResponseRedirect(redirect_to)
response = HttpResponseRedirect(redirect_to)
else:
return render(request, template_name, {
response = render(request, template_name, {
'title': _('Logged out')
})
else:
# Redirect to this page until the session has been cleared.
return HttpResponseRedirect(next_page or request.path)
response = HttpResponseRedirect(next_page or request.path)
response.delete_cookie('seahub_auth')
return response
def logout_then_login(request, login_url=None):
"Logs out the user if he is logged in. Then redirects to the log-in page."

View File

@@ -30,7 +30,7 @@ def validate_group_name(group_name):
"""
if len(group_name) > 255:
return False
return re.match('^[\w\s\'-.]+$', group_name, re.U)
return re.match('^[\w\s\'\.-]+$', group_name, re.U)
def check_group_name_conflict(request, new_group_name):
"""Check if new group name conflict with existed group.

View File

@@ -54,6 +54,7 @@
canAddGroup: {% if user.permissions.can_add_group %} true {% else %} false {% endif %},
canGenerateShareLink: {% if user.permissions.can_generate_share_link %} true {% else %} false {% endif %},
canGenerateUploadLink: {% if user.permissions.can_generate_upload_link %} true {% else %} false {% endif %},
canSendShareLinkEmail: {% if user.permissions.can_send_share_link_mail %} true {% else %} false {% endif %},
canViewOrg:'{{ user.permissions.can_view_org }}',
fileAuditEnabled: {% if file_audit_enabled %} true {% else %} false {% endif %},
enableFileComment: {% if enableFileComment %} true {% else %} false {% endif %},

View File

@@ -11,6 +11,7 @@ window.app.pageOptions = {
userNickName: '{{request.user.username|email2nickname|escapejs}}',
canGenerateShareLink: {% if user.permissions.can_generate_share_link %} true {% else %} false {% endif %},
canSendShareLinkEmail: {% if user.permissions.can_send_share_link_mail %} true {% else %} false {% endif %},
shareLinkPasswordMinLength: {{ share_link_password_min_length }},
shareLinkExpireDaysDefault: {{ share_link_expire_days_default }},
shareLinkExpireDaysMin: {{ share_link_expire_days_min }},

View File

@@ -46,6 +46,7 @@
shareLinkExpireDaysMin: '{{ share_link_expire_days_min }}',
shareLinkExpireDaysMax: '{{ share_link_expire_days_max }}',
canGenerateShareLink: {% if user.permissions.can_generate_share_link %} true {% else %} false {% endif %},
canSendShareLinkEmail: {% if user.permissions.can_send_share_link_mail %} true {% else %} false {% endif %},
isLocked: {% if file_locked %}true{% else %}false{% endif %},
lockedByMe: {% if locked_by_me %}true{% else %}false{% endif %},
canLockUnlockFile: {% if can_lock_unlock_file %}true{% else %}false{% endif %},

View File

@@ -10,9 +10,9 @@ from .settings import *
# enlarge api throttle
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'ping': '600/minute',
'anon': '5000/minute',
'user': '300/minute',
'ping': '90000/minute',
'anon': '90000/minute',
'user': '90000/minute',
},
}

View File

@@ -9,6 +9,12 @@ from seahub.test_utils import BaseTestCase
from seahub.group.utils import is_group_admin
from tests.common.utils import randstring
try:
from seahub.settings import LOCAL_PRO_DEV_ENV
except ImportError:
LOCAL_PRO_DEV_ENV = False
class RepoTrashTest(BaseTestCase):
def setUp(self):
@@ -89,6 +95,9 @@ class RepoTrashTest(BaseTestCase):
assert len(json_resp['data']) == 0
def test_can_clean_department_repo_trash(self):
if not LOCAL_PRO_DEV_ENV:
return
# create a department
group_id = ccnet_api.create_group('department_test', 'system admin', parent_group_id=-1)
seafile_api.set_group_quota(group_id, -2)

View File

@@ -9,12 +9,7 @@ SEAHUB_SRCDIR=$(dirname "${SEAHUB_TESTSDIR}")
cd "$SEAHUB_SRCDIR"
# install phantomjs
# curl -L -o /tmp/phantomjs.tar.bz2 https://dl.bintray.com/seafile-org/generic/phantomjs/phantomjs-1.9.7-linux-x86_64.tar.bz2
# tar -C /tmp -xf /tmp/phantomjs.tar.bz2
# sudo install -m 755 /tmp/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/bin/phantomjs
sudo apt-get install -y phantomjs nginx
sudo apt-get install -y nginx
sudo mv /etc/nginx/sites-enabled/default /etc/nginx/default.backup
cat <<'EOF' >/tmp/seafile.conf
server {

View File

@@ -26,8 +26,8 @@ fi
set -x
SEAHUB_TESTSDIR=$(python -c "import os; print os.path.dirname(os.path.realpath('$0'))")
SEAHUB_SRCDIR=$(dirname "${SEAHUB_TESTSDIR}")
local_settings_py=${SEAHUB_SRCDIR}/seahub/local_settings.py
export SEAHUB_LOG_DIR='/tmp/logs'
export PYTHONPATH="/usr/local/lib/python2.7/site-packages:/usr/lib/python2.7/site-packages:${SEAHUB_SRCDIR}/thirdpart:${PYTHONPATH}"
cd "$SEAHUB_SRCDIR"
set +x
@@ -43,14 +43,10 @@ function init() {
# create admin
$PYTHON -c "import ccnet; pool = ccnet.ClientPool('${CCNET_CONF_DIR}'); ccnet_threaded_rpc = ccnet.CcnetThreadedRpcClient(pool, req_pool=True); ccnet_threaded_rpc.add_emailuser('${SEAHUB_TEST_ADMIN_USERNAME}', '${SEAHUB_TEST_ADMIN_PASSWORD}', 1, 1);"
# enlarge anon api throttling settings in settings.py, this is a workaround
# to make tests pass, otherwise a few tests will be throttlled.
# TODO: cache api token.
echo "REST_FRAMEWORK = {'DEFAULT_THROTTLE_RATES': {'ping': '600/minute', 'anon': '5000/minute', 'user': '300/minute',},}" >> "${local_settings_py}"
}
function start_seahub() {
$PYTHON ./manage.py runserver 1>/tmp/seahub.access.log 2>&1 &
$PYTHON ./manage.py runserver 1>/tmp/logs/seahub.access.log 2>&1 &
sleep 5
}
@@ -60,24 +56,13 @@ function make_dist() {
make dist
}
function check_phantom_js() {
if ! which phantomjs >/dev/null; then
echo "Please install phantojs first:"
echo
echo " On ubuntu: sudo apt-get install phantomjs"
echo " On MacOSX: Download the binary from http://phantomjs.org/download.html"
exit 1
fi
}
function run_tests() {
check_phantom_js
set +e
py.test $nose_opts tests
rvalue=$?
if [[ ${TRAVIS} != "" ]]; then
# On travis-ci, dump seahub logs when test finished
for logfile in /tmp/ccnet/*.log /tmp/seafile-data/*.log /tmp/seahub*.log; do
for logfile in /tmp/logs/*.log; do
echo -e "\nLog file $logfile:\n"
cat "${logfile}"
echo