From 8ad88ab062dc36402ab101e9d73fea14e0378af7 Mon Sep 17 00:00:00 2001 From: LeoSirius Date: Tue, 2 Jul 2019 11:06:39 +0800 Subject: [PATCH 01/15] add expire days to upload link --- .../components/dialog/generate-upload-link.js | 87 +++++++++++++++---- frontend/src/models/shared-upload-info.js | 2 + .../src/pages/share-admin/upload-links.js | 29 ++++++- seahub/api2/endpoints/upload_links.py | 22 ++++- seahub/share/models.py | 6 ++ 5 files changed, 124 insertions(+), 22 deletions(-) diff --git a/frontend/src/components/dialog/generate-upload-link.js b/frontend/src/components/dialog/generate-upload-link.js index 05a24e9294..cb349b2140 100644 --- a/frontend/src/components/dialog/generate-upload-link.js +++ b/frontend/src/components/dialog/generate-upload-link.js @@ -1,6 +1,7 @@ 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, shareLinkPasswordMinLength, canSendShareLinkEmail } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; @@ -25,7 +26,9 @@ class GenerateUploadLink extends React.Component { password: '', passwdnew: '', sharedUploadInfo: null, - isSendLinkShown: false + isSendLinkShown: false, + isExpireChecked: false, + expireDays: 0, }; } @@ -90,29 +93,61 @@ class GenerateUploadLink extends React.Component { generateUploadLink = () => { let path = this.props.itemPath; let repoID = this.props.repoID; + let { password, expireDays } = this.state; - if (this.state.showPasswordInput && (this.state.password == '')) { - this.setState({ - errorInfo: gettext('Please enter password') - }); - } - else if (this.state.showPasswordInput && (this.state.showPasswordInput && this.state.password.length < shareLinkPasswordMinLength)) { - this.setState({ - errorInfo: gettext('Password is too short') - }); - } - else if (this.state.showPasswordInput && (this.state.password !== this.state.passwordnew)) { - this.setState({ - errorInfo: gettext('Passwords don\'t match') - }); - } else { - seafileAPI.createUploadLink(repoID, path, this.state.password).then((res) => { + let isValid = this.validateParamsInput(); + if (isValid) { + seafileAPI.createUploadLink(repoID, path, password, expireDays).then((res) => { let sharedUploadInfo = new SharedUploadInfo(res.data); this.setState({sharedUploadInfo: sharedUploadInfo}); }); } } + validateParamsInput = () => { + let { showPasswordInput , password, passwordnew, isExpireChecked, expireDays } = this.state; + + // check password params + if (showPasswordInput) { + if (password.length === 0) { + this.setState({errorInfo: 'Please enter password'}); + return false; + } + if (password.length < shareLinkPasswordMinLength) { + this.setState({errorInfo: 'Password is too short'}); + return false; + } + if (password !== passwordnew) { + this.setState({errorInfo: 'Passwords don\'t match'}); + return false; + } + } + + // check expire day params + let reg = /^\d+$/; + if (isExpireChecked) { + if (!expireDays) { + this.setState({errorInfo: 'Please enter days'}); + return false; + } + if (!reg.test(expireDays)) { + this.setState({errorInfo: 'Please enter a non-negative integer'}); + return false; + } + this.setState({expireDays: parseInt(expireDays)}); + } + return true; + } + + onExpireChecked = (e) => { + this.setState({isExpireChecked: e.target.checked}); + } + + onExpireDaysChanged = (e) => { + let day = e.target.value.trim(); + this.setState({expireDays: day}); + } + onCopyUploadLink = () => { let uploadLink = this.state.sharedUploadInfo.link; copy(uploadLink); @@ -156,6 +191,12 @@ class GenerateUploadLink extends React.Component { + {sharedUploadInfo.expire_date && ( + +
{gettext('Expiration Date:')}
+
{moment(sharedUploadInfo.expire_date).format('YYYY-MM-DD hh:mm:ss')}
+
+ )} {canSendShareLinkEmail && !isSendLinkShown && } {!isSendLinkShown && } @@ -192,6 +233,18 @@ class GenerateUploadLink extends React.Component { } + + + + {this.state.isExpireChecked && + + + + } {this.state.errorInfo && {this.state.errorInfo}} diff --git a/frontend/src/models/shared-upload-info.js b/frontend/src/models/shared-upload-info.js index e9776e62e9..cd7f0f9b8c 100644 --- a/frontend/src/models/shared-upload-info.js +++ b/frontend/src/models/shared-upload-info.js @@ -10,6 +10,8 @@ class SharedUploadInfo { this.ctime = object.ctime; this.token = object.token; this.view_cnt = object.view_cnt; + this.expire_date = object.expire_date; + this.is_expired = object.is_expired; } } diff --git a/frontend/src/pages/share-admin/upload-links.js b/frontend/src/pages/share-admin/upload-links.js index 97d3efb2ae..a3e25f953d 100644 --- a/frontend/src/pages/share-admin/upload-links.js +++ b/frontend/src/pages/share-admin/upload-links.js @@ -1,5 +1,6 @@ -import React, { Component } from 'react'; +import React, { Component, Fragment } from 'react'; import { Link } from '@reach/router'; +import moment from 'moment'; import { Modal, ModalHeader, ModalBody } from 'reactstrap'; import { gettext, siteRoot, loginUrl, canGenerateShareLink } from '../../utils/constants'; import { seafileAPI } from '../../utils/seafile-api'; @@ -52,9 +53,10 @@ class Content extends Component { {/*icon*/} - {gettext('Name')} - {gettext('Library')} - {gettext('Visits')} + {gettext('Name')} + {gettext('Library')} + {gettext('Visits')} + {gettext('Expiration')} {/*Operations*/} @@ -114,6 +116,24 @@ class Item extends Component { return { iconUrl, uploadUrl }; } + renderExpriedData = () => { + let item = this.props.item; + if (!item.expire_date) { + return ( + -- + ); + } + let expire_date = moment(item.expire_date).format('YYYY-MM-DD'); + return ( + + {item.is_expired ? + {expire_date} : + expire_date + } + + ); + } + render() { let item = this.props.item; let { iconUrl, uploadUrl } = this.getUploadParams(); @@ -128,6 +148,7 @@ class Item extends Component { {item.obj_name} {item.repo_name} {item.view_cnt} + {this.renderExpriedData()} diff --git a/seahub/api2/endpoints/upload_links.py b/seahub/api2/endpoints/upload_links.py index 03777cc832..290b0ebff7 100644 --- a/seahub/api2/endpoints/upload_links.py +++ b/seahub/api2/endpoints/upload_links.py @@ -2,6 +2,7 @@ import os import logging from constance import config +from dateutil.relativedelta import relativedelta from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated @@ -9,6 +10,7 @@ from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import status +from django.utils import timezone from django.utils.translation import ugettext as _ from seaserv import seafile_api @@ -48,6 +50,11 @@ def get_upload_link_info(uls): else: ctime = '' + if uls.expire_date: + expire_date = datetime_to_isoformat_timestr(uls.expire_date) + else: + expire_date = '' + data['repo_id'] = repo_id data['repo_name'] = repo.repo_name if repo else '' data['path'] = path @@ -57,6 +64,8 @@ def get_upload_link_info(uls): data['link'] = gen_shared_upload_link(token) data['token'] = token data['username'] = uls.username + data['expire_date'] = expire_date + data['is_expired'] = uls.is_expired() return data @@ -143,6 +152,12 @@ class UploadLinks(APIView): error_msg = _('Password is too short') return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + try: + expire_days = int(request.data.get('expire_days', 0)) + except ValueError: + error_msg = 'expire_days invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + # resource check repo = seafile_api.get_repo(repo_id) if not repo: @@ -164,11 +179,16 @@ class UploadLinks(APIView): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) + if expire_days <= 0: + expire_date = None + else: + expire_date = timezone.now() + relativedelta(days=expire_days) + username = request.user.username uls = UploadLinkShare.objects.get_upload_link_by_path(username, repo_id, path) if not uls: uls = UploadLinkShare.objects.create_upload_link_share(username, - repo_id, path, password) + repo_id, path, password, expire_date) link_info = get_upload_link_info(uls) return Response(link_info) diff --git a/seahub/share/models.py b/seahub/share/models.py index 408ab90772..6291cc5683 100644 --- a/seahub/share/models.py +++ b/seahub/share/models.py @@ -451,6 +451,12 @@ class UploadLinkShare(models.Model): def is_owner(self, owner): return owner == self.username + def is_expired(self): + if self.expire_date is not None and timezone.now() > self.expire_date: + return True + else: + return False + class PrivateFileDirShareManager(models.Manager): def add_private_file_share(self, from_user, to_user, repo_id, path, perm): """ From 5209ec46712ba296ff55845a9f5ad19ee86fe9ab Mon Sep 17 00:00:00 2001 From: LeoSirius Date: Thu, 4 Jul 2019 13:49:16 +0800 Subject: [PATCH 02/15] group member leave group --- .../components/dialog/leave-group-dialog.js | 44 +++++++++++++++++++ frontend/src/pages/groups/group-view.js | 28 +++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 frontend/src/components/dialog/leave-group-dialog.js diff --git a/frontend/src/components/dialog/leave-group-dialog.js b/frontend/src/components/dialog/leave-group-dialog.js new file mode 100644 index 0000000000..62989fb2eb --- /dev/null +++ b/frontend/src/components/dialog/leave-group-dialog.js @@ -0,0 +1,44 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { gettext, username } from '../../utils/constants'; +import { seafileAPI } from '../../utils/seafile-api'; +import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap'; + +class LeaveGroupDialog extends React.Component { + + constructor(props) { + super(props); + } + + dismissGroup = () => { + let that = this; + seafileAPI.quitGroup(this.props.groupID, username).then((res)=> { + that.props.onGroupChanged(); + }); + } + + render() { + return( + + {gettext('Leave Group')} + + {gettext('Really want to leave this group?')} + + + + + + + ); + } +} + +const LeaveGroupDialogPropTypes = { + toggleLeaveGroupDialog: PropTypes.func.isRequired, + groupID: PropTypes.string.isRequired, + onGroupChanged: PropTypes.func.isRequired, +}; + +LeaveGroupDialog.propTypes = LeaveGroupDialogPropTypes; + +export default LeaveGroupDialog; diff --git a/frontend/src/pages/groups/group-view.js b/frontend/src/pages/groups/group-view.js index b1ee881984..b6b7f7164c 100644 --- a/frontend/src/pages/groups/group-view.js +++ b/frontend/src/pages/groups/group-view.js @@ -20,6 +20,7 @@ import RenameGroupDialog from '../../components/dialog/rename-group-dialog'; import TransferGroupDialog from '../../components/dialog/transfer-group-dialog'; // import ImportMembersDialog from '../../components/dialog/import-members-dialog'; import ManageMembersDialog from '../../components/dialog/manage-members-dialog'; +import LeaveGroupDialog from '../../components/dialog/leave-group-dialog'; import SharedRepoListView from '../../components/shared-repo-list-view/shared-repo-list-view'; import LibDetail from '../../components/dirent-detail/lib-details'; @@ -60,6 +61,7 @@ class GroupView extends React.Component { showManageMembersDialog: false, groupMembers: [], isShowDetails: false, + showLeaveGroupDialog: false, }; } @@ -307,6 +309,13 @@ class GroupView extends React.Component { }); } + toggleLeaveGroupDialog = () => { + this.setState({ + showLeaveGroupDialog: !this.state.showLeaveGroupDialog, + showGroupDropdown: false, + }); + } + listGroupMembers = () => { seafileAPI.listGroupMembers(this.props.groupID).then((res) => { this.setState({ @@ -407,7 +416,7 @@ class GroupView extends React.Component { )}
- { (isShowSettingIcon && this.state.isStaff) && + { (isShowSettingIcon) && @@ -419,6 +428,7 @@ class GroupView extends React.Component { onClick={this.toggleGroupDropdown}>
+ {(this.state.isStaff || this.state.isOwner) && + } + {(this.state.isStaff || this.state.isOwner) && + } { this.state.isOwner && } + {/* gourp owner only can dissmiss group, admin could not quit, department member could not quit */} + {(!this.state.isOwner && !this.state.isStaff && !isDepartmentGroup) && + + }
@@ -557,6 +576,13 @@ class GroupView extends React.Component { isOwner={this.state.isOwner} /> } + {this.state.showLeaveGroupDialog && + + } ); } From 446d074066bb0fb3c38e27258deffab77a69e618 Mon Sep 17 00:00:00 2001 From: LeoSirius Date: Thu, 4 Jul 2019 15:01:06 +0800 Subject: [PATCH 03/15] add test case --- tests/api/endpoints/test_upload_links.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/tests/api/endpoints/test_upload_links.py b/tests/api/endpoints/test_upload_links.py index 98534e9c59..e2337830f3 100644 --- a/tests/api/endpoints/test_upload_links.py +++ b/tests/api/endpoints/test_upload_links.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- import json from mock import patch +from dateutil.relativedelta import relativedelta +from django.utils import timezone from django.core.urlresolvers import reverse @@ -29,9 +31,9 @@ class UploadLinksTest(BaseTestCase): def tearDown(self): self.remove_repo() - def _add_upload_link(self): + def _add_upload_link(self, expire_date=None): upload_link = UploadLinkShare.objects.create_upload_link_share(self.user_name, - self.repo_id, self.folder_path, None, None) + self.repo_id, self.folder_path, None, expire_date=expire_date) return upload_link.token @@ -50,6 +52,8 @@ class UploadLinksTest(BaseTestCase): assert json_resp[0]['link'] is not None assert json_resp[0]['token'] is not None + assert json_resp[0]['is_expired'] is not None + assert token in json_resp[0]['link'] assert 'u/d' in json_resp[0]['link'] @@ -58,6 +62,20 @@ class UploadLinksTest(BaseTestCase): self._remove_upload_link(token) + def test_get_expired_upload_link(self): + self.login_as(self.user) + # create a upload link expired one day ago. + expire_date = timezone.now() + relativedelta(days=-1) + token = self._add_upload_link(expire_date=expire_date) + + resp = self.client.get(self.url + '?path=' + self.folder_path + '&repo_id=' + self.repo_id) + self.assertEqual(200, resp.status_code) + + json_resp = json.loads(resp.content) + assert json_resp[0]['is_expired'] == True + + self._remove_upload_link(token) + @patch.object(CanGenerateUploadLink, 'has_permission') def test_get_link_with_invalid_user_role_permission(self, mock_has_permission): self.login_as(self.user) From 0df5eb12c2baeaab7dd43af7aba1f0078c1cc03c Mon Sep 17 00:00:00 2001 From: shanshuirenjia <978987373@qq.com> Date: Thu, 4 Jul 2019 16:51:54 +0800 Subject: [PATCH 04/15] repair resumable upload bug --- frontend/src/components/file-uploader/file-uploader.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/file-uploader/file-uploader.js b/frontend/src/components/file-uploader/file-uploader.js index da30a6ad22..1bddcfd3b8 100644 --- a/frontend/src/components/file-uploader/file-uploader.js +++ b/frontend/src/components/file-uploader/file-uploader.js @@ -138,6 +138,7 @@ class FileUploader extends React.Component { let uploadedBytes = res.data.uploadedBytes; let offset = Math.floor(uploadedBytes / (1024 * 1024)); file.markChunksCompleted(offset); + this.resumable.upload(); }); } } @@ -181,7 +182,9 @@ class FileUploader extends React.Component { }); } else { this.setUploadFileList(this.resumable.files); - this.resumable.upload(); + if (!enableResumableFileUpload) { + this.resumable.upload(); + } } } else { this.setUploadFileList(this.resumable.files); From f007e58c0e1e43e4d3d5e3400d5629576c7895b6 Mon Sep 17 00:00:00 2001 From: shanshuirenjia <978987373@qq.com> Date: Thu, 4 Jul 2019 17:05:48 +0800 Subject: [PATCH 05/15] repair mutiple resumable bug --- frontend/src/components/file-uploader/file-uploader.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/file-uploader/file-uploader.js b/frontend/src/components/file-uploader/file-uploader.js index 1bddcfd3b8..5ea21b1ca8 100644 --- a/frontend/src/components/file-uploader/file-uploader.js +++ b/frontend/src/components/file-uploader/file-uploader.js @@ -188,7 +188,9 @@ class FileUploader extends React.Component { } } else { this.setUploadFileList(this.resumable.files); - this.resumable.upload(); + if (!enableResumableFileUpload) { + this.resumable.upload(); + } } } From 9920f85b9202e215c55a37945bb65763201e8f9d Mon Sep 17 00:00:00 2001 From: LeoSirius Date: Thu, 4 Jul 2019 18:14:13 +0800 Subject: [PATCH 06/15] add gettext, modify UI --- frontend/src/components/dialog/generate-upload-link.js | 10 +++++----- frontend/src/pages/share-admin/upload-links.js | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/dialog/generate-upload-link.js b/frontend/src/components/dialog/generate-upload-link.js index cb349b2140..1983fc2818 100644 --- a/frontend/src/components/dialog/generate-upload-link.js +++ b/frontend/src/components/dialog/generate-upload-link.js @@ -110,15 +110,15 @@ class GenerateUploadLink extends React.Component { // check password params if (showPasswordInput) { if (password.length === 0) { - this.setState({errorInfo: 'Please enter password'}); + this.setState({errorInfo: gettext('Please enter password')}); return false; } if (password.length < shareLinkPasswordMinLength) { - this.setState({errorInfo: 'Password is too short'}); + this.setState({errorInfo: gettext('Password is too short')}); return false; } if (password !== passwordnew) { - this.setState({errorInfo: 'Passwords don\'t match'}); + this.setState({errorInfo: gettext('Passwords don\'t match')}); return false; } } @@ -127,11 +127,11 @@ class GenerateUploadLink extends React.Component { let reg = /^\d+$/; if (isExpireChecked) { if (!expireDays) { - this.setState({errorInfo: 'Please enter days'}); + this.setState({errorInfo: gettext('Please enter days')}); return false; } if (!reg.test(expireDays)) { - this.setState({errorInfo: 'Please enter a non-negative integer'}); + this.setState({errorInfo: gettext('Please enter a non-negative integer')}); return false; } this.setState({expireDays: parseInt(expireDays)}); diff --git a/frontend/src/pages/share-admin/upload-links.js b/frontend/src/pages/share-admin/upload-links.js index a3e25f953d..130d26b7e3 100644 --- a/frontend/src/pages/share-admin/upload-links.js +++ b/frontend/src/pages/share-admin/upload-links.js @@ -53,10 +53,10 @@ class Content extends Component { {/*icon*/} - {gettext('Name')} - {gettext('Library')} - {gettext('Visits')} - {gettext('Expiration')} + {gettext('Name')} + {gettext('Library')} + {gettext('Visits')} + {gettext('Expiration')} {/*Operations*/} From 7211ac3ab31f10190f5d9d1485529aced9f47ee8 Mon Sep 17 00:00:00 2001 From: shanshuirenjia <978987373@qq.com> Date: Thu, 4 Jul 2019 18:49:16 +0800 Subject: [PATCH 07/15] repair upload bug --- .../components/file-uploader/file-uploader.js | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/frontend/src/components/file-uploader/file-uploader.js b/frontend/src/components/file-uploader/file-uploader.js index 5ea21b1ca8..265d8dc080 100644 --- a/frontend/src/components/file-uploader/file-uploader.js +++ b/frontend/src/components/file-uploader/file-uploader.js @@ -128,44 +128,31 @@ class FileUploader extends React.Component { this.resumable.on('dragstart', this.onDragStart.bind(this)); } - onChunkingComplete = (file) => { - if (file.relativePath !== file.fileName) { - return; // is upload a folder; - } - if (enableResumableFileUpload) { - let repoID = this.props.repoID; - seafileAPI.getFileUploadedBytes(repoID, this.props.path, file.fileName).then(res => { - let uploadedBytes = res.data.uploadedBytes; - let offset = Math.floor(uploadedBytes / (1024 * 1024)); - file.markChunksCompleted(offset); - this.resumable.upload(); - }); - } - } - - onFileAdded = (resumableFile, files) => { - //get parent_dir、relative_path; + onChunkingComplete = (resumableFile) => { + //get parent_dir relative_path let path = this.props.path === '/' ? '/' : this.props.path + '/'; let fileName = resumableFile.fileName; let relativePath = resumableFile.relativePath; let isFile = fileName === relativePath; - //update formdata; + //update formdata resumableFile.formData = {}; - if (isFile) { + if (isFile) { // upload file resumableFile.formData = { parent_dir: path, }; - } else { + } else { // upload folder let relative_path = relativePath.slice(0, relativePath.lastIndexOf('/') + 1); resumableFile.formData = { parent_dir: path, relative_path: relative_path }; } + } - //check repetition - //uploading is file and only upload one file + onFileAdded = (resumableFile, files) => { + let isFile = resumableFile.fileName === resumableFile.relativePath; + // uploading is file and only upload one file if (isFile && files.length === 1) { let hasRepetition = false; let direntList = this.props.direntList; @@ -182,18 +169,28 @@ class FileUploader extends React.Component { }); } else { this.setUploadFileList(this.resumable.files); - if (!enableResumableFileUpload) { - this.resumable.upload(); - } + this.resumableUpload(resumableFile); } - } else { + } else { this.setUploadFileList(this.resumable.files); - if (!enableResumableFileUpload) { + if (isFile) { + this.resumableUpload(resumableFile); + } else { this.resumable.upload(); } } } + resumableUpload = (resumableFile) => { + let { repoID, path } = this.props; + seafileAPI.getFileUploadedBytes(repoID, path, resumableFile.fileName).then(res => { + let uploadedBytes = res.data.uploadedBytes; + let offset = Math.floor(uploadedBytes / (1024 * 1024)); + resumableFile.markChunksCompleted(offset); + this.resumable.upload(); + }); + } + filesAddedComplete = (resumable, files) => { // single file uploading can check repetition, because custom dialog conn't prevent program execution; } From 70a5f74788be59d62bf32f43437037af9adc7895 Mon Sep 17 00:00:00 2001 From: LeoSirius Date: Fri, 5 Jul 2019 11:05:26 +0800 Subject: [PATCH 08/15] optimize code --- frontend/src/components/dialog/leave-group-dialog.js | 9 ++++----- frontend/src/pages/groups/group-view.js | 10 +++++----- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/dialog/leave-group-dialog.js b/frontend/src/components/dialog/leave-group-dialog.js index 62989fb2eb..c5caf9997f 100644 --- a/frontend/src/components/dialog/leave-group-dialog.js +++ b/frontend/src/components/dialog/leave-group-dialog.js @@ -10,10 +10,9 @@ class LeaveGroupDialog extends React.Component { super(props); } - dismissGroup = () => { - let that = this; + leaveGroup = () => { seafileAPI.quitGroup(this.props.groupID, username).then((res)=> { - that.props.onGroupChanged(); + this.props.onGroupChanged(); }); } @@ -22,11 +21,11 @@ class LeaveGroupDialog extends React.Component { {gettext('Leave Group')} - {gettext('Really want to leave this group?')} +

{gettext('Really want to leave this group?')}

- +
); diff --git a/frontend/src/pages/groups/group-view.js b/frontend/src/pages/groups/group-view.js index b6b7f7164c..a72869ab34 100644 --- a/frontend/src/pages/groups/group-view.js +++ b/frontend/src/pages/groups/group-view.js @@ -61,7 +61,7 @@ class GroupView extends React.Component { showManageMembersDialog: false, groupMembers: [], isShowDetails: false, - showLeaveGroupDialog: false, + isLeaveGroupDialogOpen: false, }; } @@ -311,7 +311,7 @@ class GroupView extends React.Component { toggleLeaveGroupDialog = () => { this.setState({ - showLeaveGroupDialog: !this.state.showLeaveGroupDialog, + isLeaveGroupDialogOpen: !this.state.isLeaveGroupDialogOpen, showGroupDropdown: false, }); } @@ -416,7 +416,7 @@ class GroupView extends React.Component { )}
- { (isShowSettingIcon) && + { isShowSettingIcon && @@ -452,7 +452,7 @@ class GroupView extends React.Component { {/* gourp owner only can dissmiss group, admin could not quit, department member could not quit */} {(!this.state.isOwner && !this.state.isStaff && !isDepartmentGroup) && }
@@ -576,7 +576,7 @@ class GroupView extends React.Component { isOwner={this.state.isOwner} /> } - {this.state.showLeaveGroupDialog && + {this.state.isLeaveGroupDialogOpen && Date: Fri, 5 Jul 2019 11:54:04 +0800 Subject: [PATCH 09/15] update version --- frontend/package-lock.json | 6 +++--- frontend/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 68dbac5b4e..96014429e6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -13360,9 +13360,9 @@ } }, "seafile-js": { - "version": "0.2.101", - "resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.101.tgz", - "integrity": "sha512-CqF+4FKnUhnUYKCjiVbp10GkI9Ej+d4UfaWRvdGNaR74tK+0D9dUq7RNXUGS/MpIAlif7hbz5k+LUFafkfGmNg==", + "version": "0.2.104", + "resolved": "https://registry.npmjs.org/seafile-js/-/seafile-js-0.2.104.tgz", + "integrity": "sha512-KtNamxIi9YIyPqalau7yQcAbuFOskLLm+hwR9cLSEtspxDGDlyGEO2J8+MOlonJB++PY5eV6iTX6ZSnh9t5rEg==", "requires": { "axios": "^0.18.0", "form-data": "^2.3.2", diff --git a/frontend/package.json b/frontend/package.json index 8e61419cb4..bc04ee9b30 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -38,7 +38,7 @@ "react-responsive": "^6.1.1", "react-select": "^2.4.1", "reactstrap": "^6.4.0", - "seafile-js": "^0.2.101", + "seafile-js": "^0.2.104", "socket.io-client": "^2.2.0", "sw-precache-webpack-plugin": "0.11.4", "unified": "^7.0.0", From e19696e63c985baa2a5579600863c14cafb67fff Mon Sep 17 00:00:00 2001 From: LeoSirius Date: Fri, 5 Jul 2019 15:28:13 +0800 Subject: [PATCH 10/15] add check condition to send file info api --- .../src/components/dialog/generate-share-link.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/dialog/generate-share-link.js b/frontend/src/components/dialog/generate-share-link.js index c6929b5378..d03de0404b 100644 --- a/frontend/src/components/dialog/generate-share-link.js +++ b/frontend/src/components/dialog/generate-share-link.js @@ -41,6 +41,7 @@ class GenerateShareLink extends React.Component { 'can_download': true }; this.isExpireDaysNoLimit = (parseInt(shareLinkExpireDaysMin) === 0 && parseInt(shareLinkExpireDaysMax) === 0); + this.isOfficeFile = Utils.isOfficeFile(this.props.itemPath); } componentDidMount() { @@ -57,12 +58,13 @@ class GenerateShareLink extends React.Component { this.setState({isLoading: false}); } }); - - seafileAPI.getFileInfo(repoID, path).then((res) => { - if (res.data) { - this.setState({fileInfo: res.data}); - } - }); + if (this.isOfficeFile) { + seafileAPI.getFileInfo(repoID, path).then((res) => { + if (res.data) { + this.setState({fileInfo: res.data}); + } + }); + } } onPasswordInputChecked = () => { @@ -402,7 +404,7 @@ class GenerateShareLink extends React.Component { this.setPermission('preview')} />{' '}{gettext('Preview only')} - {(Utils.isOfficeFile(this.props.itemPath) && fileInfo && fileInfo.can_edit) && + {(this.isOfficeFile && fileInfo && fileInfo.can_edit) &&