1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-16 15:19:06 +00:00

add can_share_repo role permission (#6234)

* add can_share_repo role permission

* update

* update

---------

Co-authored-by: r350178982 <32759763+r350178982@users.noreply.github.com>
This commit is contained in:
lian
2024-06-24 10:05:12 +08:00
committed by GitHub
parent ce19f90ec5
commit 2694bfffa5
11 changed files with 96 additions and 38 deletions

View File

@@ -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 &&
<Fragment>
<NavItem role="tab" aria-selected={activeTab === 'shareToUser'} aria-controls="share-to-user-panel">
<NavLink className={activeTab === 'shareToUser' ? 'active' : ''} onClick={this.toggle.bind(this, 'shareToUser')} tabIndex="0" onKeyDown={this.onTabKeyDown}>
{gettext('Share to user')}
</NavLink>
</NavItem>
<NavItem role="tab" aria-selected={activeTab === 'shareToGroup'} aria-controls="share-to-group-panel">
<NavLink className={activeTab === 'shareToGroup' ? 'active' : ''} onClick={this.toggle.bind(this, 'shareToGroup')} tabIndex="0" onKeyDown={this.onTabKeyDown}>
{gettext('Share to group')}
</NavLink>
</NavItem>
{isPro && !isCustomPermission && (
{ canShareRepo && (
<NavItem role="tab" aria-selected={activeTab === 'shareToUser'} aria-controls="share-to-user-panel">
<NavLink className={activeTab === 'shareToUser' ? 'active' : ''} onClick={this.toggle.bind(this, 'shareToUser')} tabIndex="0" onKeyDown={this.onTabKeyDown}>
{gettext('Share to user')}
</NavLink>
</NavItem>
)}
{ canShareRepo && (
<NavItem role="tab" aria-selected={activeTab === 'shareToGroup'} aria-controls="share-to-group-panel">
<NavLink className={activeTab === 'shareToGroup' ? 'active' : ''} onClick={this.toggle.bind(this, 'shareToGroup')} tabIndex="0" onKeyDown={this.onTabKeyDown}>
{gettext('Share to group')}
</NavLink>
</NavItem>
)}
{isPro && !isCustomPermission && canShareRepo && (
<NavItem role="tab" aria-selected={activeTab === 'customSharePermission'} aria-controls="custom-share-perm-panel">
<NavLink className={activeTab === 'customSharePermission' ? 'active' : ''} onClick={this.toggle.bind(this, 'customSharePermission')} tabIndex="0" onKeyDown={this.onTabKeyDown}>
{gettext('Custom sharing permissions')}

View File

@@ -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 (
<ul className={`nav sub-nav nav-pills flex-column ${this.state.sharedExtended ? 'side-panel-slide' : 'side-panel-slide-up'}`} style={style} >
{canAddRepo && (
{canAddRepo && canShareRepo && (
<li className="nav-item">
<Link to={siteRoot + 'share-admin-libs/'} className={`nav-link ellipsis ${this.getActiveClass('share-admin-libs')}`} title={gettext('Libraries')} onClick={(e) => this.tabItemClick(e, 'share-admin-libs')}>
<span aria-hidden="true" className="sharp">#</span>
@@ -146,12 +146,14 @@ class MainSideNav extends React.Component {
</Link>
</li>
)}
<li className="nav-item">
<Link to={siteRoot + 'share-admin-folders/'} className={`nav-link ellipsis ${this.getActiveClass('share-admin-folders')}`} title={gettext('Folders')} onClick={(e) => this.tabItemClick(e, 'share-admin-folders')}>
<span aria-hidden="true" className="sharp">#</span>
<span className="nav-text">{gettext('Folders')}</span>
</Link>
</li>
{canShareRepo && (
<li className="nav-item">
<Link to={siteRoot + 'share-admin-folders/'} className={`nav-link ellipsis ${this.getActiveClass('share-admin-folders')}`} title={gettext('Folders')} onClick={(e) => this.tabItemClick(e, 'share-admin-folders')}>
<span aria-hidden="true" className="sharp">#</span>
<span className="nav-text">{gettext('Folders')}</span>
</Link>
</li>
)}
{linksNavItem}
</ul>
);

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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:

View File

@@ -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')

View File

@@ -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,

View File

@@ -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 %},

View File

@@ -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