1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-05 00:43:53 +00:00

return repo/folder permission when get share link list (#4319)

* return repo/folder permission when get share link list

* update permission check when create/update share link

* optimized code

* optimized code

* add can_edit valid

* return can_edit field when get share link list
This commit is contained in:
杨顺强
2019-12-03 13:52:52 +08:00
committed by Daniel Pan
parent c3a6ada019
commit 50e0618a7d
5 changed files with 180 additions and 113 deletions

View File

@@ -76,8 +76,9 @@ class GenerateShareLink extends React.Component {
getDirentInfoAPI = seafileAPI.getDirInfo(repoID, path); getDirentInfoAPI = seafileAPI.getDirInfo(repoID, path);
} }
getDirentInfoAPI.then((res) => { getDirentInfoAPI.then((res) => {
let canEdit = res.data.can_edit;
let permission = res.data.permission; let permission = res.data.permission;
let permissionOptions = Utils.getShareLinkPermissionList(this.props.itemType, permission, path); let permissionOptions = Utils.getShareLinkPermissionList(this.props.itemType, permission, path, canEdit);
this.setState({ this.setState({
permissionOptions: permissionOptions, permissionOptions: permissionOptions,
currentPermission: permissionOptions[0], currentPermission: permissionOptions[0],

View File

@@ -6,6 +6,8 @@ class ShareLink {
this.path = object.path; this.path = object.path;
this.obj_name = object.obj_name; this.obj_name = object.obj_name;
this.is_dir = object.is_dir; this.is_dir = object.is_dir;
this.can_edit = object.can_edit;
this.repo_folder_permission = object.repo_folder_permission;
this.permissions = object.permissions; this.permissions = object.permissions;
this.username = object.username; this.username = object.username;
this.is_expired = object.is_expired; this.is_expired = object.is_expired;

View File

@@ -109,28 +109,13 @@ class Item extends Component {
updatePermissionOptions = () => { updatePermissionOptions = () => {
const item = this.props.item; const item = this.props.item;
if (item.is_dir && item.path === '/') { let itemType = item.is_dir ? (item.path === '/' ? 'library' : 'dir') : 'file';
let permissionOptions = Utils.getShareLinkPermissionList('library', '', item.path); let permission = item.repo_folder_permission;
this.setState({ let permissionOptions = Utils.getShareLinkPermissionList(itemType, permission, item.path, item.can_edit);
permissionOptions: permissionOptions, let currentPermission = this.getCurrentPermission();
});
} else {
let { repo_id, path } = item;
let getDirentInfoAPI = item.is_dir ? seafileAPI.getDirInfo(repo_id, path) : seafileAPI.getFileInfo(repo_id, path);
getDirentInfoAPI.then((res) => {
let itemType = item.is_dir ? 'dir' : 'file';
let permission = res.data.permission;
let permissionOptions = Utils.getShareLinkPermissionList(itemType, permission, item.path);
this.setState({
permissionOptions: permissionOptions,
});
}).catch(error => {
let errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
});
}
this.setState({ this.setState({
currentPermission: this.getCurrentPermission(), permissionOptions: permissionOptions,
currentPermission: currentPermission
}); });
} }

View File

@@ -116,7 +116,7 @@ export const Utils = {
} }
}, },
getShareLinkPermissionList: function(itemType, permission, path) { getShareLinkPermissionList: function(itemType, permission = null, path, canEdit = null) {
// itemType: library, dir, file // itemType: library, dir, file
// permission: rw, r, admin, cloud-edit, preview // permission: rw, r, admin, cloud-edit, preview
@@ -139,12 +139,15 @@ export const Utils = {
if (permission == 'rw' || permission == 'admin' || permission == 'r') { if (permission == 'rw' || permission == 'admin' || permission == 'r') {
permissionOptions.push(downloadOption); permissionOptions.push(downloadOption);
} }
if (this.isEditableOfficeFile(path) && (permission == 'rw' || permission == 'admin')) { if (this.isEditableOfficeFile(path) && (permission == 'rw' || permission == 'admin') && canEdit) {
permissionOptions.push(editDownloadOption); permissionOptions.push(editDownloadOption);
} }
if (this.isEditableOfficeFile(path) && (permission == 'cloud-edit')) {
permissionOptions.push(editOnly); // not support
} // if (this.isEditableOfficeFile(path) && (permission == 'cloud-edit')) {
// permissionOptions.push(editOnly);
// }
} }
return permissionOptions; return permissionOptions;
}, },

View File

@@ -1,6 +1,7 @@
# Copyright (c) 2012-2016 Seafile Ltd. # Copyright (c) 2012-2016 Seafile Ltd.
import os import os
import stat import stat
import json
import logging import logging
import posixpath import posixpath
from constance import config from constance import config
@@ -23,7 +24,8 @@ from seahub.api2.utils import api_error
from seahub.api2.authentication import TokenAuthentication from seahub.api2.authentication import TokenAuthentication
from seahub.api2.throttling import UserRateThrottle from seahub.api2.throttling import UserRateThrottle
from seahub.api2.permissions import CanGenerateShareLink, IsProVersion from seahub.api2.permissions import CanGenerateShareLink, IsProVersion
from seahub.constants import PERMISSION_READ_WRITE from seahub.constants import PERMISSION_READ_WRITE, PERMISSION_READ, \
PERMISSION_PREVIEW_EDIT, PERMISSION_PREVIEW
from seahub.share.models import FileShare, check_share_link_access from seahub.share.models import FileShare, check_share_link_access
from seahub.utils import gen_shared_link, is_org_context, normalize_file_path, \ from seahub.utils import gen_shared_link, is_org_context, normalize_file_path, \
normalize_dir_path, is_pro_version, get_file_type_and_ext normalize_dir_path, is_pro_version, get_file_type_and_ext
@@ -39,6 +41,7 @@ from seahub.settings import SHARE_LINK_EXPIRE_DAYS_MAX, \
ENABLE_SHARE_LINK_AUDIT, ENABLE_VIDEO_THUMBNAIL, \ ENABLE_SHARE_LINK_AUDIT, ENABLE_VIDEO_THUMBNAIL, \
THUMBNAIL_ROOT THUMBNAIL_ROOT
from seahub.wiki.models import Wiki from seahub.wiki.models import Wiki
from seahub.views.file import can_edit_file
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -85,32 +88,31 @@ def get_share_link_info(fileshare):
data['expire_date'] = expire_date data['expire_date'] = expire_date
data['is_expired'] = fileshare.is_expired() data['is_expired'] = fileshare.is_expired()
data['permissions'] = fileshare.get_permissions() data['permissions'] = fileshare.get_permissions()
data['can_edit'] = False
if repo and path != '/' and not data['is_dir']:
dirent = seafile_api.get_dirent_by_path(repo_id, path)
try:
can_edit, _ = can_edit_file(obj_name, dirent.size, repo)
data['can_edit'] = can_edit
except Exception as e:
logger.error(e)
return data return data
def check_permissions_arg(request): def check_permissions_arg(request):
permissions = request.data.get('permissions', None)
if permissions is not None:
if isinstance(permissions, dict):
perm_dict = permissions
elif isinstance(permissions, basestring):
import json
try:
perm_dict = json.loads(permissions)
except ValueError:
error_msg = 'permissions invalid: %s' % permissions
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
else:
error_msg = 'permissions invalid: %s' % permissions
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
else:
perm_dict = None
can_download = True permissions = request.data.get('permissions', '')
can_edit = False if not permissions:
return FileShare.PERM_VIEW_DL
if perm_dict is not None: if isinstance(permissions, dict):
can_download = perm_dict.get('can_download', True) perm_dict = permissions
can_edit = perm_dict.get('can_edit', False) elif isinstance(permissions, basestring):
perm_dict = json.loads(str(permissions))
can_edit = perm_dict.get('can_edit', False)
can_download = perm_dict.get('can_download', True)
if not can_edit and can_download: if not can_edit and can_download:
perm = FileShare.PERM_VIEW_DL perm = FileShare.PERM_VIEW_DL
@@ -132,18 +134,6 @@ class ShareLinks(APIView):
permission_classes = (IsAuthenticated, CanGenerateShareLink) permission_classes = (IsAuthenticated, CanGenerateShareLink)
throttle_classes = (UserRateThrottle,) throttle_classes = (UserRateThrottle,)
def _generate_obj_id_and_type_by_path(self, repo_id, path):
file_id = seafile_api.get_file_id_by_path(repo_id, path)
if file_id:
return (file_id, 'f')
dir_id = seafile_api.get_dir_id_by_path(repo_id, path)
if dir_id:
return (dir_id, 'd')
return (None, None)
def get(self, request): def get(self, request):
""" Get all share links of a user. """ Get all share links of a user.
@@ -151,48 +141,68 @@ class ShareLinks(APIView):
1. default(NOT guest) user; 1. default(NOT guest) user;
""" """
# get all share links
username = request.user.username username = request.user.username
fileshares = FileShare.objects.filter(username=username)
repo_id = request.GET.get('repo_id', None) repo_id = request.GET.get('repo_id', '')
if repo_id: path = request.GET.get('path', '')
fileshares = []
# get all share links of current user
if not repo_id and not path:
fileshares = FileShare.objects.filter(username=username)
# share links in repo
if repo_id and not path:
repo = seafile_api.get_repo(repo_id) repo = seafile_api.get_repo(repo_id)
if not repo: if not repo:
error_msg = 'Library %s not found.' % repo_id error_msg = 'Library %s not found.' % repo_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg) return api_error(status.HTTP_404_NOT_FOUND, error_msg)
# filter share links by repo fileshares = FileShare.objects.filter(username=username) \
fileshares = filter(lambda fs: fs.repo_id == repo_id, fileshares) .filter(repo_id=repo_id)
path = request.GET.get('path', None) # share links by repo and path
if path: if repo_id and path:
try: repo = seafile_api.get_repo(repo_id)
obj_id, s_type = self._generate_obj_id_and_type_by_path(repo_id, path) if not repo:
except SearpcError as e: error_msg = 'Library %s not found.' % repo_id
logger.error(e) return api_error(status.HTTP_404_NOT_FOUND, error_msg)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
if not obj_id:
if s_type == 'f':
error_msg = 'file %s not found.' % path
elif s_type == 'd':
error_msg = 'folder %s not found.' % path
else:
error_msg = 'path %s not found.' % path
if path != '/':
dirent = seafile_api.get_dirent_by_path(repo_id, path)
if not dirent:
error_msg = 'Dirent %s not found.' % path
return api_error(status.HTTP_404_NOT_FOUND, error_msg) return api_error(status.HTTP_404_NOT_FOUND, error_msg)
# if path invalid, filter share links by repo if stat.S_ISDIR(dirent.mode):
if s_type == 'd' and path[-1] != '/': path = normalize_dir_path(path)
path = path + '/' else:
path = normalize_file_path(path)
fileshares = filter(lambda fs: fs.path == path, fileshares) fileshares = FileShare.objects.filter(username=username) \
.filter(repo_id=repo_id) \
.filter(path=path)
repo_folder_permission_dict = {}
for fileshare in fileshares:
if fileshare.s_type == 'd':
folder_path = normalize_dir_path(fileshare.path)
else:
file_path = normalize_file_path(fileshare.path)
folder_path = os.path.dirname(file_path)
repo_id = fileshare.repo_id
if repo_id not in repo_folder_permission_dict:
permission = seafile_api.check_permission_by_path(repo_id,
folder_path, fileshare.username)
repo_folder_permission_dict[repo_id] = permission
links_info = [] links_info = []
for fs in fileshares: for fs in fileshares:
link_info = get_share_link_info(fs) link_info = get_share_link_info(fs)
link_info['repo_folder_permission'] = \
repo_folder_permission_dict.get(link_info['repo_id'], '')
links_info.append(link_info) links_info.append(link_info)
if len(links_info) == 1: if len(links_info) == 1:
@@ -258,7 +268,11 @@ class ShareLinks(APIView):
else: else:
expire_date = timezone.now() + relativedelta(days=expire_days) expire_date = timezone.now() + relativedelta(days=expire_days)
perm = check_permissions_arg(request) try:
perm = check_permissions_arg(request)
except Exception:
error_msg = 'permissions invalid.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# resource check # resource check
repo = seafile_api.get_repo(repo_id) repo = seafile_api.get_repo(repo_id)
@@ -266,33 +280,45 @@ class ShareLinks(APIView):
error_msg = 'Library %s not found.' % repo_id error_msg = 'Library %s not found.' % repo_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg) return api_error(status.HTTP_404_NOT_FOUND, error_msg)
if path != '/':
dirent = seafile_api.get_dirent_by_path(repo_id, path)
if not dirent:
error_msg = 'Dirent %s not found.' % path
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
# permission check
if repo.encrypted: if repo.encrypted:
error_msg = 'Permission denied.' error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg) return api_error(status.HTTP_403_FORBIDDEN, error_msg)
try:
obj_id, s_type = self._generate_obj_id_and_type_by_path(repo_id, path)
except SearpcError as e:
logger.error(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
if not obj_id:
if s_type == 'f':
error_msg = 'file %s not found.' % path
elif s_type == 'd':
error_msg = 'folder %s not found.' % path
else:
error_msg = 'path %s not found.' % path
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
username = request.user.username username = request.user.username
permission_by_path = seafile_api.check_permission_by_path(repo_id, path, username) repo_folder_permission = seafile_api.check_permission_by_path(repo_id, path, username)
if parse_repo_perm(permission_by_path).can_generate_share_link is False: if parse_repo_perm(repo_folder_permission).can_generate_share_link is False:
error_msg = 'Permission denied.' error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg) return api_error(status.HTTP_403_FORBIDDEN, error_msg)
if repo_folder_permission in (PERMISSION_PREVIEW_EDIT, PERMISSION_PREVIEW) \
and perm != FileShare.PERM_VIEW_ONLY:
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
if repo_folder_permission in (PERMISSION_READ) \
and perm not in (FileShare.PERM_VIEW_DL, FileShare.PERM_VIEW_ONLY):
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
if path != '/':
s_type = 'd' if stat.S_ISDIR(dirent.mode) else 'f'
if s_type == 'f':
file_name = os.path.basename(path.rstrip('/'))
can_edit, _ = can_edit_file(file_name, dirent.size, repo)
if not can_edit and perm in (FileShare.PERM_EDIT_DL, FileShare.PERM_EDIT_ONLY):
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
else:
s_type = 'd'
# create share link
org_id = request.user.org.org_id if is_org_context(request) else None org_id = request.user.org.org_id if is_org_context(request) else None
if s_type == 'f': if s_type == 'f':
fs = FileShare.objects.get_file_link_by_path(username, repo_id, path) fs = FileShare.objects.get_file_link_by_path(username, repo_id, path)
@@ -344,22 +370,72 @@ class ShareLink(APIView):
share link creater share link creater
""" """
# argument check
try:
perm = check_permissions_arg(request)
except Exception:
error_msg = 'permissions invalud.'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
# resource check
try: try:
fs = FileShare.objects.get(token=token) fs = FileShare.objects.get(token=token)
except FileShare.DoesNotExist: except FileShare.DoesNotExist:
error_msg = 'token %s not found.' % token error_msg = 'token %s not found.' % token
return api_error(status.HTTP_404_NOT_FOUND, error_msg) return api_error(status.HTTP_404_NOT_FOUND, error_msg)
repo_id = fs.repo_id
repo = seafile_api.get_repo(repo_id)
if not repo_id:
error_msg = 'Library %s not found.' % repo_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
if fs.path != '/':
dirent = seafile_api.get_dirent_by_path(repo_id, fs.path)
if not dirent:
error_msg = 'Dirent %s not found.' % repo_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
# permission check
username = request.user.username username = request.user.username
if not fs.is_owner(username): if not fs.is_owner(username):
error_msg = 'Permission denied.' error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg) return api_error(status.HTTP_403_FORBIDDEN, error_msg)
permissions = request.data.get('permissions', None) # get permission of origin repo/folder
if permissions: if fs.s_type == 'd':
perm = check_permissions_arg(request) folder_path = normalize_dir_path(fs.path)
fs.permission = perm else:
fs.save() file_path = normalize_file_path(fs.path)
folder_path = os.path.dirname(file_path)
username = request.user.username
repo_folder_permission = seafile_api.check_permission_by_path(repo_id,
folder_path, username)
if not repo_folder_permission:
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
if repo_folder_permission in (PERMISSION_PREVIEW_EDIT, PERMISSION_PREVIEW) \
and perm != FileShare.PERM_VIEW_ONLY:
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
if repo_folder_permission in (PERMISSION_READ) \
and perm not in (FileShare.PERM_VIEW_DL, FileShare.PERM_VIEW_ONLY):
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
if fs.s_type == 'f':
file_name = os.path.basename(fs.path.rstrip('/'))
can_edit, _ = can_edit_file(file_name, dirent.size, repo)
if not can_edit and perm in (FileShare.PERM_EDIT_DL, FileShare.PERM_EDIT_ONLY):
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
# update share link permission
fs.permission = perm
fs.save()
link_info = get_share_link_info(fs) link_info = get_share_link_info(fs)
return Response(link_info) return Response(link_info)
@@ -454,7 +530,7 @@ class ShareLinkOnlineOfficeLock(APIView):
# refresh lock file # refresh lock file
try: try:
seafile_api.refresh_file_lock(repo_id, path) seafile_api.refresh_file_lock(repo_id, path)
except SearpcError, e: except SearpcError as e:
logger.error(e) logger.error(e)
error_msg = 'Internal Server Error' error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)