From 9276c5380c05e5a53e3dd6cc6d6e0f90439745b3 Mon Sep 17 00:00:00 2001 From: lian Date: Sat, 11 Nov 2023 17:14:07 +0800 Subject: [PATCH 1/6] update get share links api (#5755) fix bug when share link file's parent folder no longer exists --- seahub/api2/endpoints/share_links.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/seahub/api2/endpoints/share_links.py b/seahub/api2/endpoints/share_links.py index 6afe80ca83..cdb33d143b 100644 --- a/seahub/api2/endpoints/share_links.py +++ b/seahub/api2/endpoints/share_links.py @@ -234,8 +234,13 @@ class ShareLinks(APIView): tmp_key = f"{repo_id}_{path}" if tmp_key not in repo_folder_permission_dict: - permission = seafile_api.check_permission_by_path(repo_id, path, username) - repo_folder_permission_dict[tmp_key] = permission + try: + permission = seafile_api.check_permission_by_path(repo_id, + path, + username) + repo_folder_permission_dict[tmp_key] = permission + except Exception: + repo_folder_permission_dict[tmp_key] = '' links_info = [] for fs in fileshares: From 79448fe0f9d75d474dc1d3c45f6204aa82ecade3 Mon Sep 17 00:00:00 2001 From: lian Date: Thu, 16 Nov 2023 16:53:19 +0800 Subject: [PATCH 2/6] fix bug when save text file (#5766) --- frontend/src/view-file-text.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/view-file-text.js b/frontend/src/view-file-text.js index c9ab543b65..0b469877e6 100644 --- a/frontend/src/view-file-text.js +++ b/frontend/src/view-file-text.js @@ -7,6 +7,7 @@ import FileView from './components/file-view/file-view'; import SeafileCodeMirror from './components/seafile-codemirror'; import FileViewTip from './components/file-view/file-view-tip'; import { seafileAPI } from './utils/seafile-api'; +import { Utils } from './utils/utils'; import './css/text-file-view.css'; const { @@ -64,7 +65,7 @@ class ViewFileText extends React.Component { if (!this.isParticipant) { this.addParticipant(); } - let dirPath = '/'; + let dirPath = Utils.getDirName(filePath); return ( seafileAPI.getUpdateLink(repoID, dirPath).then((res) => { const uploadLink = res.data; From 2bdba64bd129f4abc860e70985030641f35e5d8d Mon Sep 17 00:00:00 2001 From: WJH <40563566+loveclever@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:33:20 +0800 Subject: [PATCH 3/6] patch for WOPI (#5787) --- seahub/wopi/views.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/seahub/wopi/views.py b/seahub/wopi/views.py index 2ce488fd16..f775e07cda 100644 --- a/seahub/wopi/views.py +++ b/seahub/wopi/views.py @@ -229,7 +229,7 @@ class WOPIFilesView(APIView): dirent = seafile_api.get_dirent_by_path(repo_id, file_path) if dirent: last_modified = datetime.datetime.utcfromtimestamp(dirent.mtime) - result['LastModifiedTime'] = last_modified.isoformat() + result['LastModifiedTime'] = last_modified.strftime('%Y-%m-%dT%H:%M:%S.%fZ') except Exception as e: logger.error(e) return HttpResponse(json.dumps({}), status=500, @@ -244,14 +244,16 @@ class WOPIFilesView(APIView): absolute_uri = request.build_absolute_uri('/') result['PostMessageOrigin'] = urllib.parse.urljoin(absolute_uri, SITE_ROOT).strip('/') - result['HideSaveOption'] = True - result['HideExportOption'] = True + result['HideSaveOption'] = True if not can_edit else False + result['HideExportOption'] = True if not can_download else False result['EnableOwnerTermination'] = True result['SupportsLocks'] = True result['SupportsGetLock'] = True result['DisablePrint'] = True if not can_download else False result['HidePrintOption'] = True if not can_download else False + result['DisableCopy'] = True if not can_download else False + result['DisableExport'] = True if not can_download else False result['SupportsUpdate'] = True if can_edit else False result['UserCanWrite'] = True if can_edit else False @@ -445,14 +447,22 @@ class WOPIFilesContentsView(APIView): resp = requests.post(update_url, files=files, data=data) if resp.status_code != 200: logger.error('update_url: {}'.format(update_url)) - logger.error('parameter file: {}'.format(files['file'][:100])) - logger.error('parameter file_name: {}'.format(files['file_name'])) - logger.error('parameter target_file: {}'.format(files['target_file'])) + logger.error('parameter file: {}'.format(files['file'][1][:100])) + logger.error('parameter file_name: {}'.format(files['file'][0])) + logger.error('parameter target_file: {}'.format(data['target_file'])) logger.error('response: {}'.format(resp.__dict__)) + return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) except Exception as e: logger.error(e) return HttpResponse(json.dumps({}), status=500, content_type=json_content_type) - return HttpResponse(json.dumps({}), status=200, - content_type=json_content_type) + result = dict() + try: + dirent = seafile_api.get_dirent_by_path(repo_id, file_path) + if dirent: + last_modified = datetime.datetime.utcfromtimestamp(dirent.mtime) + result['LastModifiedTime'] = last_modified.strftime('%Y-%m-%dT%H:%M:%S.%fZ') + except Exception as e: + logger.error(e) + return HttpResponse(json.dumps(result), status=200, content_type=json_content_type) From 7b3ca29ae3f60c1a400743cd761cd46e48a74d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E9=A1=BA=E5=BC=BA?= <978987373@qq.com> Date: Fri, 24 Nov 2023 11:46:48 +0800 Subject: [PATCH 4/6] optimize code (#5785) * optimize code * update --------- Co-authored-by: lian --- frontend/package-lock.json | 29 ++++++++++--------- frontend/package.json | 1 + .../components/seafile-codemirror/index.js | 2 ++ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 496563769a..d4da444527 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "seahub-frontend", "version": "0.1.0", "dependencies": { + "@codemirror/view": "^6.22.0", "@gatsbyjs/reach-router": "1.3.9", "@seafile/react-image-lightbox": "2.0.2", "@seafile/resumablejs": "1.1.16", @@ -2791,12 +2792,12 @@ } }, "node_modules/@codemirror/view": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.7.1.tgz", - "integrity": "sha512-kYtS+uqYw/q/0ytYxpkqE1JVuK5NsbmBklWYhwLFTKO9gVuTdh/kDEeZPKorbqHcJ+P+ucrhcsS1czVweOpT2g==", + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.22.0.tgz", + "integrity": "sha512-6zLj4YIoIpfTGKrDMTbeZRpa8ih4EymMCKmddEDcJWrCdp/N1D46B38YEz4creTb4T177AVS9EyXkLeC/HL2jA==", "dependencies": { "@codemirror/state": "^6.1.4", - "style-mod": "^4.0.0", + "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, @@ -25785,9 +25786,9 @@ } }, "node_modules/style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.0.tgz", + "integrity": "sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA==" }, "node_modules/stylehacks": { "version": "4.0.3", @@ -31220,12 +31221,12 @@ } }, "@codemirror/view": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.7.1.tgz", - "integrity": "sha512-kYtS+uqYw/q/0ytYxpkqE1JVuK5NsbmBklWYhwLFTKO9gVuTdh/kDEeZPKorbqHcJ+P+ucrhcsS1czVweOpT2g==", + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.22.0.tgz", + "integrity": "sha512-6zLj4YIoIpfTGKrDMTbeZRpa8ih4EymMCKmddEDcJWrCdp/N1D46B38YEz4creTb4T177AVS9EyXkLeC/HL2jA==", "requires": { "@codemirror/state": "^6.1.4", - "style-mod": "^4.0.0", + "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, @@ -47523,9 +47524,9 @@ } }, "style-mod": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", - "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.0.tgz", + "integrity": "sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA==" }, "stylehacks": { "version": "4.0.3", diff --git a/frontend/package.json b/frontend/package.json index d73bff9631..0a5f8af4c4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@codemirror/view": "^6.22.0", "@gatsbyjs/reach-router": "1.3.9", "@seafile/react-image-lightbox": "2.0.2", "@seafile/resumablejs": "1.1.16", diff --git a/frontend/src/components/seafile-codemirror/index.js b/frontend/src/components/seafile-codemirror/index.js index 066ca99565..04dd8b98fe 100644 --- a/frontend/src/components/seafile-codemirror/index.js +++ b/frontend/src/components/seafile-codemirror/index.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import CodeMirror from '@uiw/react-codemirror'; +import { EditorView } from "@codemirror/view" import { loadLanguage } from '@uiw/codemirror-extensions-langs'; import { Utils } from '../../utils/utils'; @@ -64,6 +65,7 @@ class SeafileCodeMirror extends React.Component { {...options} onChange={this.onChange} basicSetup={DEFAULT_CODEMIRROR_OPTIONS} + extensions={[EditorView.lineWrapping]} /> ); From 99397644be16a44bcb1745dfe14a528cf525e0ac Mon Sep 17 00:00:00 2001 From: WJH <40563566+loveclever@users.noreply.github.com> Date: Mon, 4 Dec 2023 17:01:06 +0800 Subject: [PATCH 5/6] notify org admin when user froze (#5811) --- seahub/auth/views.py | 2 +- seahub/base/accounts.py | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/seahub/auth/views.py b/seahub/auth/views.py index 98c32bca0f..2adced94fa 100644 --- a/seahub/auth/views.py +++ b/seahub/auth/views.py @@ -142,7 +142,7 @@ def login(request, template_name='registration/login.html', try: user = User.objects.get(email) if user.is_active: - user.freeze_user(notify_admins=True) + user.freeze_user(notify_admins=True, notify_org_admins=True) logger.warn('Login attempt limit reached, freeze the user email/username: %s, ip: %s, attemps: %d' % (login, ip, failed_attempt)) except User.DoesNotExist: diff --git a/seahub/base/accounts.py b/seahub/base/accounts.py index 69f30122aa..6634f0b554 100644 --- a/seahub/base/accounts.py +++ b/seahub/base/accounts.py @@ -468,7 +468,7 @@ class User(object): "Sends an e-mail to this User." send_mail(subject, message, from_email, [self.email]) - def freeze_user(self, notify_admins=False): + def freeze_user(self, notify_admins=False, notify_org_admins=False): self.is_active = False self.save() @@ -492,6 +492,37 @@ class User(object): # restore current language translation.activate(cur_language) + if notify_org_admins: + org = None + if is_pro_version(): + orgs = ccnet_api.get_orgs_by_user(self.username) + if orgs: + org = orgs[0] + + org_members = list() + if org: + org_members = ccnet_api.get_org_emailusers(org.url_prefix, -1, -1) + for u in org_members: + if not (ccnet_api.is_org_staff(org.org_id, u.email) == 1): + continue + + # save current language + cur_language = translation.get_language() + + # get and active user language + user_language = Profile.objects.get_user_language(u.email) + translation.activate(user_language) + + send_html_email_with_dj_template(u.email, + subject=_('Account %(account)s froze on %(site)s.') % { + "account": self.email, + "site": get_site_name()}, + dj_template='sysadmin/user_freeze_email.html', + context={'user': self.email}) + + # restore current language + translation.activate(cur_language) + def remove_repo_passwds(self): """ Remove all repo decryption passwords stored on server. From c7a77675a14266ab309f10166a06b44cebcd207d Mon Sep 17 00:00:00 2001 From: WJH <40563566+loveclever@users.noreply.github.com> Date: Thu, 11 Jan 2024 14:46:32 +0800 Subject: [PATCH 6/6] fix org admin change user status (#5889) --- frontend/src/pages/org-admin/org-user-item.js | 1 + .../pages/org-admin/org-users-search-users.js | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/org-admin/org-user-item.js b/frontend/src/pages/org-admin/org-user-item.js index 4036337b50..6183c96a92 100644 --- a/frontend/src/pages/org-admin/org-user-item.js +++ b/frontend/src/pages/org-admin/org-user-item.js @@ -15,6 +15,7 @@ const propTypes = { toggleDelete: PropTypes.func.isRequired, onFreezedItem: PropTypes.func.isRequired, onUnfreezedItem: PropTypes.func.isRequired, + changeStatus: PropTypes.func.isRequired, }; class UserItem extends React.Component { diff --git a/frontend/src/pages/org-admin/org-users-search-users.js b/frontend/src/pages/org-admin/org-users-search-users.js index e8cb1f51a9..bd8e38cda8 100644 --- a/frontend/src/pages/org-admin/org-users-search-users.js +++ b/frontend/src/pages/org-admin/org-users-search-users.js @@ -25,7 +25,7 @@ class OrgUsersSearchUsersResult extends React.Component { } render() { - let { orgUsers } = this.props; + let { orgUsers, changeStatus } = this.props; return (
@@ -51,6 +51,7 @@ class OrgUsersSearchUsersResult extends React.Component { toggleDelete={this.props.toggleDelete} onFreezedItem={this.onFreezedItem} onUnfreezedItem={this.onUnfreezedItem} + changeStatus={changeStatus} /> );})} @@ -151,6 +152,22 @@ class OrgUsersSearchUsers extends Component { } } + changeStatus= (email, isActive) => { + seafileAPI.orgAdminChangeOrgUserStatus(orgID, email, isActive).then(res => { + let users = this.state.orgUsers.map(item => { + if (item.email == email) { + item['is_active']= res.data['is_active']; + } + return item; + }); + this.setState({orgUsers: users}); + toaster.success(gettext('Edit succeeded.')); + }).catch(error => { + let errMessage = Utils.getErrorMsg(error); + toaster.danger(errMessage); + }); + } + render() { const { query, isSubmitBtnActive } = this.state; @@ -181,6 +198,7 @@ class OrgUsersSearchUsers extends Component {

{gettext('Result')}