diff --git a/frontend/src/components/dialog/share-dialog.js b/frontend/src/components/dialog/share-dialog.js index 4848c7a088..f2b9f526d3 100644 --- a/frontend/src/components/dialog/share-dialog.js +++ b/frontend/src/components/dialog/share-dialog.js @@ -1,7 +1,7 @@ import React, { Fragment } from 'react'; import PropTypes from 'prop-types'; import { Modal, ModalHeader, ModalBody, TabContent, TabPane, Nav, NavItem, NavLink } from 'reactstrap'; -import { gettext, username, canGenerateShareLink, canGenerateUploadLink, canInvitePeople, additionalShareDialogNote, enableOCM, isPro } from '../../utils/constants'; +import { gettext, username, canGenerateShareLink, canGenerateUploadLink, canInvitePeople, additionalShareDialogNote, enableOCM, isPro, canShareRepo } from '../../utils/constants'; import ShareLinkPanel from '../share-link-panel'; import GenerateUploadLink from './generate-upload-link'; import ShareToUser from './share-to-user'; @@ -131,17 +131,21 @@ class ShareDialog extends React.Component { } {enableDirPrivateShare && - - - {gettext('Share to user')} - - - - - {gettext('Share to group')} - - - {isPro && !isCustomPermission && ( + { canShareRepo && ( + + + {gettext('Share to user')} + + + )} + { canShareRepo && ( + + + {gettext('Share to group')} + + + )} + {isPro && !isCustomPermission && canShareRepo && ( {gettext('Custom sharing permissions')} diff --git a/frontend/src/components/main-side-nav.js b/frontend/src/components/main-side-nav.js index 5faf778594..a6eb591bf1 100644 --- a/frontend/src/components/main-side-nav.js +++ b/frontend/src/components/main-side-nav.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Link } from '@gatsbyjs/reach-router'; -import { gettext, siteRoot, canAddRepo, canGenerateShareLink, canGenerateUploadLink, canInvitePeople, enableOCM, enableOCMViaWebdav } from '../utils/constants'; +import { gettext, siteRoot, canAddRepo, canShareRepo, canGenerateShareLink, canGenerateUploadLink, canInvitePeople, enableOCM, enableOCMViaWebdav } from '../utils/constants'; import { seafileAPI } from '../utils/seafile-api'; import { Utils } from '../utils/utils'; import toaster from './toast'; @@ -138,7 +138,7 @@ class MainSideNav extends React.Component { } return (
    - {canAddRepo && ( + {canAddRepo && canShareRepo && (
  • this.tabItemClick(e, 'share-admin-libs')}> @@ -146,12 +146,14 @@ class MainSideNav extends React.Component {
  • )} -
  • - this.tabItemClick(e, 'share-admin-folders')}> - - {gettext('Folders')} - -
  • + {canShareRepo && ( +
  • + this.tabItemClick(e, 'share-admin-folders')}> + + {gettext('Folders')} + +
  • + )} {linksNavItem}
); diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js index 4fdae8c652..d77fe24b1d 100644 --- a/frontend/src/utils/constants.js +++ b/frontend/src/utils/constants.js @@ -37,6 +37,7 @@ export const name = window.app.pageOptions.name; export const contactEmail = window.app.pageOptions.contactEmail; export const username = window.app.pageOptions.username; export const canAddRepo = window.app.pageOptions.canAddRepo; +export const canShareRepo = window.app.pageOptions.canShareRepo; export const canAddGroup = window.app.pageOptions.canAddGroup; export const groupImportMembersExtraMsg = window.app.pageOptions.groupImportMembersExtraMsg; export const canGenerateShareLink = window.app.pageOptions.canGenerateShareLink; diff --git a/seahub/api2/endpoints/custom_share_permissions.py b/seahub/api2/endpoints/custom_share_permissions.py index cf259fd401..66cff48d65 100644 --- a/seahub/api2/endpoints/custom_share_permissions.py +++ b/seahub/api2/endpoints/custom_share_permissions.py @@ -29,6 +29,9 @@ class CustomSharePermissionsView(APIView): """List custom share permissions """ # permission check + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + if not check_folder_permission(request, repo_id, '/'): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) @@ -53,6 +56,9 @@ class CustomSharePermissionsView(APIView): def post(self, request, repo_id): """Add a custom share permission """ + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + username = request.user.username # argument check permission = request.data.get('permission', None) @@ -98,6 +104,9 @@ class CustomSharePermissionView(APIView): """get a custom share permission """ # permission check + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + if not check_folder_permission(request, repo_id, '/'): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) @@ -122,6 +131,9 @@ class CustomSharePermissionView(APIView): """Update a custom share permission """ # argument check + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + permission = request.data.get('permission', None) if not permission: error_msg = 'permission invalid.' @@ -170,6 +182,9 @@ class CustomSharePermissionView(APIView): def delete(self, request, repo_id, permission_id): """Delete a custom share permission """ + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + username = request.user.username # permission check diff --git a/seahub/api2/endpoints/dir_shared_items.py b/seahub/api2/endpoints/dir_shared_items.py index dd85799e72..79bfbc863d 100644 --- a/seahub/api2/endpoints/dir_shared_items.py +++ b/seahub/api2/endpoints/dir_shared_items.py @@ -61,10 +61,13 @@ class DirSharedItemsEndpoint(APIView): org_id = request.user.org.org_id if path == '/': share_items = seafile_api.list_org_repo_shared_to(org_id, - repo_owner, repo_id) + repo_owner, + repo_id) else: share_items = seafile_api.get_org_shared_users_for_subdir(org_id, - repo_id, path, repo_owner) + repo_id, + path, + repo_owner) else: repo_owner = seafile_api.get_repo_owner(repo_id) if path == '/': @@ -98,10 +101,13 @@ class DirSharedItemsEndpoint(APIView): org_id = request.user.org.org_id if path == '/': share_items = seafile_api.list_org_repo_shared_group(org_id, - repo_owner, repo_id) + repo_owner, + repo_id) else: share_items = seafile_api.get_org_shared_groups_for_subdir(org_id, - repo_id, path, repo_owner) + repo_id, + path, + repo_owner) else: repo_owner = seafile_api.get_repo_owner(repo_id) if path == '/': @@ -129,11 +135,10 @@ class DirSharedItemsEndpoint(APIView): org_id, repo_id, path, repo_owner, group_id) else: if path == '/': - seafile_api.unset_group_repo(repo_id, group_id, - repo_owner) + seafile_api.unset_group_repo(repo_id, group_id, repo_owner) else: - seafile_api.unshare_subdir_for_group( - repo_id, path, repo_owner, group_id) + seafile_api.unshare_subdir_for_group(repo_id, path, + repo_owner, group_id) continue ret.append({ @@ -197,6 +202,9 @@ class DirSharedItemsEndpoint(APIView): def get(self, request, repo_id, format=None): """List shared items(shared to users/groups) for a folder/library. """ + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + repo = seafile_api.get_repo(repo_id) if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Library %s not found.' % repo_id) @@ -220,6 +228,9 @@ class DirSharedItemsEndpoint(APIView): def post(self, request, repo_id, format=None): """Update shared item permission. """ + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + username = request.user.username repo = seafile_api.get_repo(repo_id) if not repo: @@ -305,6 +316,10 @@ class DirSharedItemsEndpoint(APIView): content_type=json_content_type) def put(self, request, repo_id, format=None): + + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + username = request.user.username repo = seafile_api.get_repo(repo_id) if not repo: @@ -368,8 +383,7 @@ class DirSharedItemsEndpoint(APIView): if not is_org_user(to_user, int(org_id)): org_name = request.user.org.org_name - error_msg = 'User %s is not member of organization %s.' \ - % (to_user, org_name) + error_msg = f'User {to_user} is not member of organization {org_name}.' result['failed'].append({ 'email': to_user, @@ -377,7 +391,8 @@ class DirSharedItemsEndpoint(APIView): }) continue - # when calling seafile API to share authority related functions, change the uesrname to repo owner. + # when calling seafile API to share authority related functions, + # change the uesrname to repo owner. repo_owner = seafile_api.get_org_repo_owner(repo_id) # can't share to owner if to_user == repo_owner: @@ -477,7 +492,8 @@ class DirSharedItemsEndpoint(APIView): try: org_id = None if is_org_context(request): - # when calling seafile API to share authority related functions, change the uesrname to repo owner. + # when calling seafile API to share authority related functions, + # change the uesrname to repo owner. repo_owner = seafile_api.get_org_repo_owner(repo_id) org_id = request.user.org.org_id @@ -513,9 +529,14 @@ class DirSharedItemsEndpoint(APIView): continue return HttpResponse(json.dumps(result), - status=200, content_type=json_content_type) + status=200, + content_type=json_content_type) def delete(self, request, repo_id, format=None): + + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + username = request.user.username repo = seafile_api.get_repo(repo_id) if not repo: @@ -556,7 +577,7 @@ class DirSharedItemsEndpoint(APIView): # Delete share permission at ExtraSharePermission table. if path == '/': - ExtraSharePermission.objects.delete_share_permission(repo_id, + ExtraSharePermission.objects.delete_share_permission(repo_id, shared_to) org_id = None @@ -601,8 +622,8 @@ class DirSharedItemsEndpoint(APIView): # delete share permission if repo is deleted if path == '/': - ExtraGroupsSharePermission.objects.delete_share_permission(repo_id, - group_id) + ExtraGroupsSharePermission.objects.delete_share_permission(repo_id, + group_id) send_perm_audit_msg('delete-repo-perm', username, group_id, repo_id, path, permission) diff --git a/seahub/api2/endpoints/shared_folders.py b/seahub/api2/endpoints/shared_folders.py index 1216932c2e..8e84372f10 100644 --- a/seahub/api2/endpoints/shared_folders.py +++ b/seahub/api2/endpoints/shared_folders.py @@ -33,6 +33,8 @@ class SharedFolders(APIView): Permission checking: 1. all authenticated user can perform this action. """ + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') shared_repos = [] username = request.user.username diff --git a/seahub/api2/endpoints/shared_repos.py b/seahub/api2/endpoints/shared_repos.py index d9fb9ec8f3..7b91c21ced 100644 --- a/seahub/api2/endpoints/shared_repos.py +++ b/seahub/api2/endpoints/shared_repos.py @@ -38,6 +38,8 @@ class SharedRepos(APIView): Permission checking: 1. all authenticated user can perform this action. """ + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') shared_repos = [] username = request.user.username @@ -128,6 +130,9 @@ class SharedRepo(APIView): Permission checking: 1. Only repo owner can update. """ + + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') # argument check permission = request.data.get('permission', None) @@ -244,7 +249,9 @@ class SharedRepo(APIView): Permission checking: 1. Only repo owner and system admin can unshare a publib library. """ - + if not request.user.permissions.can_share_repo(): + return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') + # argument check share_type = request.GET.get('share_type', None) if not share_type: diff --git a/seahub/base/accounts.py b/seahub/base/accounts.py index a7e5d8e2be..afdf06d0d5 100644 --- a/seahub/base/accounts.py +++ b/seahub/base/accounts.py @@ -359,6 +359,9 @@ class UserPermissions(object): def can_add_repo(self): return self._get_perm_by_roles('can_add_repo') + def can_share_repo(self): + return self._get_perm_by_roles('can_share_repo') + def can_add_group(self): return self._get_perm_by_roles('can_add_group') diff --git a/seahub/role_permissions/settings.py b/seahub/role_permissions/settings.py index 57d846fff4..479ea6fd37 100644 --- a/seahub/role_permissions/settings.py +++ b/seahub/role_permissions/settings.py @@ -27,6 +27,7 @@ def merge_roles(default, custom): DEFAULT_ENABLED_ROLE_PERMISSIONS = { DEFAULT_USER: { 'can_add_repo': True, + 'can_share_repo': True, 'can_add_group': True, 'can_view_org': True, 'can_add_public_repo': False, @@ -48,6 +49,7 @@ DEFAULT_ENABLED_ROLE_PERMISSIONS = { }, GUEST_USER: { 'can_add_repo': False, + 'can_share_repo': False, 'can_add_group': False, 'can_view_org': False, 'can_add_public_repo': False, diff --git a/seahub/templates/base_for_react.html b/seahub/templates/base_for_react.html index 952c0fc906..b87bf56e8e 100644 --- a/seahub/templates/base_for_react.html +++ b/seahub/templates/base_for_react.html @@ -62,6 +62,7 @@ guideEnabled: {% if guide_enabled %} true {% else %} false {% endif %}, trashReposExpireDays: {% if trash_repos_expire_days >= 0 %} {{ trash_repos_expire_days }} {% else %} null {% endif %}, canAddRepo: {% if user.permissions.can_add_repo %} true {% else %} false {% endif %}, + canShareRepo: {% if user.permissions.can_share_repo %} true {% else %} false {% endif %}, canAddGroup: {% if user.permissions.can_add_group %} true {% else %} false {% endif %}, groupImportMembersExtraMsg: "{{group_import_members_extra_msg}}", canGenerateShareLink: {% if user.permissions.can_generate_share_link %} true {% else %} false {% endif %}, diff --git a/tests/seahub/role_permissions/test_utils.py b/tests/seahub/role_permissions/test_utils.py index a24bfd8d6b..4f0a03a780 100644 --- a/tests/seahub/role_permissions/test_utils.py +++ b/tests/seahub/role_permissions/test_utils.py @@ -11,4 +11,4 @@ class UtilsTest(BaseTestCase): assert DEFAULT_USER in get_available_roles() def test_get_enabled_role_permissions_by_role(self): - assert len(list(get_enabled_role_permissions_by_role(DEFAULT_USER).keys())) == 19 + assert len(list(get_enabled_role_permissions_by_role(DEFAULT_USER).keys())) == 20