def list_group_shared_items(self, request, repo_id, path): if is_org_context(request): # 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 if path == '/': share_items = seafile_api.list_org_repo_shared_group(org_id, repo_owner, repo_id) else: share_items = seafile_api.get_org_shared_groups_for_subdir(org_id, repo_id, path, repo_owner) else: repo_owner = seafile_api.get_repo_owner(repo_id) if path == '/': share_items = seafile_api.list_repo_shared_group_by_user(repo_owner, repo_id) else: share_items = seafile_api.get_shared_groups_for_subdir(repo_id, path, repo_owner) ret = [] # change is_admin to True if user in admin groups. admin_groups = ExtraGroupsSharePermission.objects.get_admin_groups_by_repo(repo_id) for item in share_items: ret.append({ "share_type": "group", "group_info": { "id": item.group_id, "name": seaserv.get_group(item.group_id).group_name, }, "permission": item.perm, "is_admin": item.group_id in admin_groups, }) return ret
def list_group_shared_items(self, request, repo_id, path): username = request.user.username if is_org_context(request): org_id = request.user.org.org_id if path == '/': share_items = seafile_api.list_org_repo_shared_group(org_id, username, repo_id) else: share_items = seafile_api.get_org_shared_groups_for_subdir(org_id, repo_id, path, username) else: if path == '/': share_items = seafile_api.list_repo_shared_group_by_user(username, repo_id) else: share_items = seafile_api.get_shared_groups_for_subdir(repo_id, path, username) ret = [] for item in share_items: ret.append({ "share_type": "group", "group_info": { "id": item.group_id, "name": seaserv.get_group(item.group_id).group_name, }, "permission": item.perm, }) return ret
def list_group_shared_items(self, request, repo_id, path): repo_owner = seafile_api.get_repo_owner(repo_id) if path == '/': share_items = seafile_api.list_repo_shared_group_by_user(repo_owner, repo_id) else: share_items = seafile_api.get_shared_groups_for_subdir(repo_id, path, repo_owner) ret = [] for item in share_items: group_id = item.group_id group = ccnet_api.get_group(group_id) if not group: if path == '/': 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) continue ret.append({ "group_id": group_id, "group_name": group.group_name, "permission": item.perm, }) return ret
def list_group_shared_items(self, request, repo_id, path): username = request.user.username if is_org_context(request): org_id = request.user.org.org_id if path == '/': share_items = seafile_api.list_org_repo_shared_group( org_id, username, repo_id) else: share_items = seafile_api.get_org_shared_groups_for_subdir( org_id, repo_id, path, username) else: if path == '/': share_items = seafile_api.list_repo_shared_group_by_user( username, repo_id) else: share_items = seafile_api.get_shared_groups_for_subdir( repo_id, path, username) ret = [] for item in share_items: ret.append({ "share_type": "group", "group_info": { "id": item.group_id, "name": seaserv.get_group(item.group_id).group_name, }, "permission": item.perm, }) return ret
def list_group_shared_items(self, request, repo_id, path): if is_org_context(request): # 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 if path == '/': share_items = seafile_api.list_org_repo_shared_group( org_id, repo_owner, repo_id) else: share_items = seafile_api.get_org_shared_groups_for_subdir( org_id, repo_id, path, repo_owner) else: repo_owner = seafile_api.get_repo_owner(repo_id) if path == '/': share_items = seafile_api.list_repo_shared_group_by_user( repo_owner, repo_id) else: share_items = seafile_api.get_shared_groups_for_subdir( repo_id, path, repo_owner) ret = [] # change is_admin to True if user in admin groups. admin_groups = ExtraGroupsSharePermission.objects.get_admin_groups_by_repo( repo_id) for item in share_items: if '@seafile_group' in repo_owner and \ repo_owner.split('@')[0] == str(item.group_id): continue group_id = item.group_id group = ccnet_api.get_group(group_id) if not group: if is_org_context(request): if path == '/': seafile_api.del_org_group_repo(repo_id, org_id, group_id) else: seafile_api.org_unshare_subdir_for_group( org_id, repo_id, path, repo_owner, group_id) else: if path == '/': 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) continue ret.append({ "share_type": "group", "group_info": { "id": group_id, "name": group.group_name, }, "permission": item.perm, "is_admin": group_id in admin_groups, }) return ret
def get_repo_shared_users(repo_id, repo_owner, include_groups=True): """Return a list contains users and group users. Repo owner is ommited. """ ret = [] users = seafile_api.list_repo_shared_to(repo_owner, repo_id) ret += [x.user for x in users] if include_groups: for e in seafile_api.list_repo_shared_group_by_user(repo_owner, repo_id): g_members = seaserv.get_group_members(e.group_id) ret += [x.user_name for x in g_members if x.user_name != repo_owner] return list(set(ret))
def get_repo_shared_to_groups(self, request, repo_id): username = request.user.username if is_org_context(request): org_id = request.user.org.org_id share_items = seafile_api.list_org_repo_shared_group( org_id, username, repo_id) else: share_items = seafile_api.list_repo_shared_group_by_user( username, repo_id) ret = [] for item in share_items: ret.append(item.group_id) return ret
def get_repo_shared_to_groups(self, request, repo_id): username = request.user.username if is_org_context(request): org_id = request.user.org.org_id share_items = seafile_api.list_org_repo_shared_group(org_id, username, repo_id) else: share_items = seafile_api.list_repo_shared_group_by_user( username, repo_id) ret = [] for item in share_items: ret.append(item.group_id) return ret
def get_shared_groups_by_repo_path(self, repo_id, repo_owner, path='/', org_id=None): if is_valid_org_id(org_id): if path == '/': return seafile_api.list_org_repo_shared_group( org_id, repo_owner, repo_id) else: return seafile_api.get_org_shared_groups_for_subdir( org_id, repo_id, path, repo_owner) else: if path == '/': return seafile_api.list_repo_shared_group_by_user( repo_owner, repo_id) else: return seafile_api.get_shared_groups_for_subdir( repo_id, path, repo_owner)
def has_shared_to_group(repo_id, path, gid, org_id=None): if org_id: # 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) if path == '/': share_items = seafile_api.list_org_repo_shared_group(org_id, repo_owner, repo_id) else: share_items = seafile_api.get_org_shared_groups_for_subdir(org_id, repo_id, path, repo_owner) else: repo_owner = seafile_api.get_repo_owner(repo_id) if path == '/': share_items = seafile_api.list_repo_shared_group_by_user(repo_owner, repo_id) else: share_items = seafile_api.get_shared_groups_for_subdir(repo_id, path, repo_owner) return gid in [item.group_id for item in share_items]
def has_shared_to_group(repo_id, path, gid, org_id=None): if is_valid_org_id(org_id): # 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) if path == '/': share_items = seafile_api.list_org_repo_shared_group(org_id, repo_owner, repo_id) else: share_items = seafile_api.get_org_shared_groups_for_subdir(org_id, repo_id, path, repo_owner) else: repo_owner = seafile_api.get_repo_owner(repo_id) if path == '/': share_items = seafile_api.list_repo_shared_group_by_user(repo_owner, repo_id) else: share_items = seafile_api.get_shared_groups_for_subdir(repo_id, path, repo_owner) return gid in [item.group_id for item in share_items]
def get(self, request, repo_id): """ Return repo share info Permission checking: 1. all authenticated user can perform this action. """ # resource check repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check permission = check_folder_permission(request, repo_id, '/') if not permission: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if is_org_context(request): org_id = request.user.org.org_id repo_owner = seafile_api.get_org_repo_owner(org_id, repo_id) shared_users = seafile_api.list_org_repo_shared_to( repo_owner, repo_id) shared_groups = seafile_api.list_org_repo_shared_group( org_id, repo_owner, repo_id) else: repo_owner = seafile_api.get_repo_owner(repo_id) shared_users = seafile_api.list_repo_shared_to(repo_owner, repo_id) shared_groups = seafile_api.list_repo_shared_group_by_user( repo_owner, repo_id) result = { "shared_user_emails": [item.user for item in shared_users], "shared_group_ids": [item.group_id for item in shared_groups], } return Response(result)
def delete(self, request, repo_id, format=None): username = request.user.username repo = seafile_api.get_repo(repo_id) if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Library %s not found.' % repo_id) path = request.GET.get('p', '/') if seafile_api.get_dir_id_by_path(repo.id, path) is None: return api_error(status.HTTP_404_NOT_FOUND, 'Folder %s not found.' % path) if username != self.get_repo_owner(request, repo_id): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') shared_to_user, shared_to_group = self.handle_shared_to_args(request) if path == '/': shared_repo = repo else: try: sub_repo = self.get_sub_repo_by_path(request, repo, path) if sub_repo: shared_repo = sub_repo else: return api_error(status.HTTP_404_NOT_FOUND, 'Sub-library not found.') except SearpcError as e: logger.error(e) return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Failed to get sub-library.') if shared_to_user: shared_to = request.GET.get('username') if shared_to is None or not is_valid_username(shared_to): return api_error(status.HTTP_400_BAD_REQUEST, 'Email %s invalid.' % shared_to) try: User.objects.get(email=shared_to) except User.DoesNotExist: return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid user, should be registered') if is_org_context(request): org_id = request.user.org.org_id seaserv.seafserv_threaded_rpc.org_remove_share( org_id, shared_repo.id, username, shared_to) else: seaserv.remove_share(shared_repo.id, username, shared_to) permission = seafile_api.check_permission_by_path( repo.id, path, shared_to) send_perm_audit_msg('delete-repo-perm', username, shared_to, repo_id, path, permission) if shared_to_group: group_id = request.GET.get('group_id') try: group_id = int(group_id) except ValueError: return api_error(status.HTTP_400_BAD_REQUEST, 'group_id %s invalid' % group_id) # hacky way to get group repo permission permission = '' for e in seafile_api.list_repo_shared_group_by_user( username, shared_repo.id): if e.group_id == group_id: permission = e.perm break if is_org_context(request): org_id = request.user.org.org_id seaserv.del_org_group_repo(shared_repo.id, org_id, group_id) else: seafile_api.unset_group_repo(shared_repo.id, group_id, username) send_perm_audit_msg('delete-repo-perm', username, group_id, repo_id, path, permission) return HttpResponse(json.dumps({'success': True}), status=200, content_type=json_content_type)
def put(self, request, repo_id, format=None): """ update a library status, transfer a library, rename a library Permission checking: 1. only admin can perform this action. """ # argument check new_status = request.data.get('status', None) if new_status: if new_status not in ('normal', 'read-only'): error_msg = 'status invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) new_repo_name = request.data.get('name', None) if new_repo_name: if not is_valid_dirent_name(new_repo_name): error_msg = 'name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) new_owner = request.data.get('owner', None) if new_owner: if not is_valid_email(new_owner): error_msg = 'owner invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # resource check repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) if new_status: try: seafile_api.set_repo_status(repo_id, normalize_repo_status_str(new_status)) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if new_repo_name: try: res = seafile_api.edit_repo(repo_id, new_repo_name, '', None) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if res == -1: e = 'Admin rename failed: ID of library is %s, edit_repo api called failed.' % \ repo_id logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if new_owner: try: new_owner_obj = User.objects.get(email=new_owner) except User.DoesNotExist: error_msg = 'User %s not found.' % new_owner return api_error(status.HTTP_404_NOT_FOUND, error_msg) if not new_owner_obj.permissions.can_add_repo(): error_msg = _('Transfer failed: role of %s is %s, can not add library.') % \ (new_owner, new_owner_obj.role) return api_error(status.HTTP_403_FORBIDDEN, error_msg) if MULTI_TENANCY: try: if seafile_api.get_org_id_by_repo_id(repo_id) > 0: error_msg = 'Can not transfer organization library.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if ccnet_api.get_orgs_by_user(new_owner): error_msg = 'Can not transfer library to organization user %s' % new_owner return api_error(status.HTTP_403_FORBIDDEN, error_msg) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) repo_owner = seafile_api.get_repo_owner(repo_id) if new_owner == repo_owner: error_msg = _("Library can not be transferred to owner.") return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # get repo shared to user/group list shared_users = seafile_api.list_repo_shared_to( repo_owner, repo_id) shared_groups = seafile_api.list_repo_shared_group_by_user( repo_owner, repo_id) # get all pub repos pub_repos = [] if not request.cloud_mode: pub_repos = seafile_api.list_inner_pub_repos_by_owner(repo_owner) # transfer repo seafile_api.set_repo_owner(repo_id, new_owner) # reshare repo to user for shared_user in shared_users: shared_username = shared_user.user if new_owner == shared_username: continue seafile_api.share_repo(repo_id, new_owner, shared_username, shared_user.perm) # reshare repo to group for shared_group in shared_groups: shared_group_id = shared_group.group_id if not is_group_member(shared_group_id, new_owner): continue seafile_api.set_group_repo(repo_id, shared_group_id, new_owner, shared_group.perm) # reshare repo to links try: UploadLinkShare.objects.filter(username=repo_owner, repo_id=repo_id).update(username=new_owner) FileShare.objects.filter(username=repo_owner, repo_id=repo_id).update(username=new_owner) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) # check if current repo is pub-repo # if YES, reshare current repo to public for pub_repo in pub_repos: if repo_id != pub_repo.id: continue seafile_api.add_inner_pub_repo(repo_id, pub_repo.permission) break # send admin operation log signal admin_op_detail = { "id": repo_id, "name": repo.name, "from": repo_owner, "to": new_owner, } admin_operation.send(sender=None, admin_name=request.user.username, operation=REPO_TRANSFER, detail=admin_op_detail) repo = seafile_api.get_repo(repo_id) repo_info = get_repo_info(repo) return Response(repo_info)
def put(self, request, repo_id, format=None): """ transfer a library Permission checking: 1. only admin can perform this action. """ repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) new_owner = request.data.get('owner', None) if not new_owner: error_msg = 'owner invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: new_owner_obj = User.objects.get(email=new_owner) except User.DoesNotExist: error_msg = 'User %s not found.' % new_owner return api_error(status.HTTP_404_NOT_FOUND, error_msg) if not new_owner_obj.permissions.can_add_repo(): error_msg = 'Transfer failed: role of %s is %s, can not add library.' % \ (new_owner, new_owner_obj.role) return api_error(status.HTTP_403_FORBIDDEN, error_msg) if MULTI_TENANCY: try: if seafserv_threaded_rpc.get_org_id_by_repo_id(repo_id) > 0: error_msg = 'Can not transfer organization library.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if ccnet_api.get_orgs_by_user(new_owner): error_msg = 'Can not transfer library to organization user %s' % new_owner return api_error(status.HTTP_403_FORBIDDEN, error_msg) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) repo_owner = seafile_api.get_repo_owner(repo_id) # get repo shared to user/group list shared_users = seafile_api.list_repo_shared_to(repo_owner, repo_id) shared_groups = seafile_api.list_repo_shared_group_by_user( repo_owner, repo_id) # get all pub repos pub_repos = [] if not request.cloud_mode: pub_repos = seafile_api.list_inner_pub_repos_by_owner(repo_owner) # transfer repo seafile_api.set_repo_owner(repo_id, new_owner) # reshare repo to user for shared_user in shared_users: shared_username = shared_user.user if new_owner == shared_username: continue seafile_api.share_repo(repo_id, new_owner, shared_username, shared_user.perm) # reshare repo to group for shared_group in shared_groups: shared_group_id = shared_group.group_id if not ccnet_api.is_group_user(shared_group_id, new_owner): continue seafile_api.set_group_repo(repo_id, shared_group_id, new_owner, shared_group.perm) # check if current repo is pub-repo # if YES, reshare current repo to public for pub_repo in pub_repos: if repo_id != pub_repo.id: continue seafile_api.add_inner_pub_repo(repo_id, pub_repo.permission) break # send admin operation log signal admin_op_detail = { "id": repo_id, "name": repo.name, "from": repo_owner, "to": new_owner, } admin_operation.send(sender=None, admin_name=request.user.username, operation=REPO_TRANSFER, detail=admin_op_detail) repo = seafile_api.get_repo(repo_id) repo_info = get_repo_info(repo) return Response(repo_info)
def get(self, request, repo, path, share_type): """ List user/group shares Permission checking: 1. admin user. """ result = [] # current `request.user.username` is admin user, # so need to identify the repo owner specifically. repo_owner = seafile_api.get_repo_owner(repo.repo_id) if share_type == 'user': try: if path == '/': share_items = seafile_api.list_repo_shared_to( repo_owner, repo.repo_id) else: share_items = seafile_api.get_shared_users_for_subdir( repo.repo_id, path, repo_owner) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) admin_users = ExtraSharePermission.objects.get_admin_users_by_repo(repo.repo_id) for share_item in share_items: user_email = share_item.user user_name = email2nickname(user_email) if user_email else '--' share_info = {} share_info['repo_id'] = repo.repo_id share_info['path'] = path share_info['share_type'] = share_type share_info['user_email'] = user_email share_info['user_name'] = user_name share_info['permission'] = share_item.perm share_info['is_admin'] = user_email in admin_users result.append(share_info) if share_type == 'group': try: if path == '/': share_items = seafile_api.list_repo_shared_group_by_user( repo_owner, repo.repo_id) else: share_items = seafile_api.get_shared_groups_for_subdir( repo.repo_id, path, repo_owner) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) admin_groups = ExtraGroupsSharePermission.objects.get_admin_groups_by_repo(repo.repo_id) for share_item in share_items: group_id = share_item.group_id group = ccnet_api.get_group(group_id) group_name = group.group_name if group else '--' share_info = {} share_info['repo_id'] = repo.repo_id share_info['path'] = path share_info['share_type'] = share_type share_info['group_id'] = group_id share_info['group_name'] = group_name share_info['permission'] = share_item.perm share_info['is_admin'] = group_id in admin_groups result.append(share_info) return Response(result)
def delete(self, request, repo_id, format=None): """ Unshare a repo. Permission checking: 1. Only repo owner can unshare a library. """ # argument check share_type = request.GET.get('share_type', None) if not share_type: error_msg = 'share_type invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if share_type not in ('personal', 'group', 'public'): error_msg = "share_type can only be 'personal' or 'group' or 'public'." return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # resource check repo = seafile_api.get_repo(repo_id) if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Library %s not found.' % repo_id) # permission check username = request.user.username if is_org_context(request): repo_owner = seafile_api.get_org_repo_owner(repo_id) else: repo_owner = seafile_api.get_repo_owner(repo_id) if username != repo_owner: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # delete share org_id = None if is_org_context(request): org_id = request.user.org.org_id if share_type == 'personal': user = request.GET.get('user', None) if not user or not is_valid_username(user): error_msg = 'user invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # if user not found, permission will be None permission = seafile_api.check_permission_by_path( repo_id, '/', user) try: if org_id: seafile_api.org_remove_share(org_id, repo_id, username, user) else: seafile_api.remove_share(repo_id, username, user) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) send_perm_audit_msg('delete-repo-perm', username, user, repo_id, '/', permission) if share_type == 'group': group_id = request.GET.get('group_id', None) if not group_id: error_msg = 'group_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: group_id = int(group_id) except ValueError: error_msg = 'group_id must be integer.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # hacky way to get group repo permission permission = '' if org_id: for e in seafile_api.list_org_repo_shared_group( org_id, username, repo_id): if e.group_id == group_id: permission = e.perm break else: for e in seafile_api.list_repo_shared_group_by_user( username, repo_id): if e.group_id == group_id: permission = e.perm break try: if org_id: seaserv.del_org_group_repo(repo_id, org_id, group_id) else: seafile_api.unset_group_repo(repo_id, group_id, username) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) send_perm_audit_msg('delete-repo-perm', username, group_id, repo_id, '/', permission) if share_type == 'public': pub_repos = [] if org_id: pub_repos = seaserv.list_org_inner_pub_repos(org_id, username) if not request.cloud_mode: pub_repos = seaserv.list_inner_pub_repos(username) try: if org_id: seaserv.seafserv_threaded_rpc.unset_org_inner_pub_repo( org_id, repo_id) else: seafile_api.remove_inner_pub_repo(repo_id) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) permission = '' for repo in pub_repos: if repo.repo_id == repo_id: permission = repo.permission break if permission: send_perm_audit_msg('delete-repo-perm', username, 'all', repo_id, '/', permission) return Response({'success': True})
def test_share_repo_to_group(repo, group, permission): assert api.check_permission(repo.id, USER) == 'rw' assert api.check_permission(repo.id, USER2) is None repos = api.get_repos_by_group(group.id) assert len(repos) == 0 group_list = ccnet_api.get_groups(USER) assert len(group_list) == 1 group_list = ccnet_api.get_groups(USER2) assert len(group_list) == 0 api.group_share_repo(repo.id, group.id, USER, permission) repos = api.get_repos_by_group(group.id) assert_repo_with_permission(repo, repos, permission) group_ids = api.get_shared_group_ids_by_repo(repo.id) assert group_ids[0] == str(group.id) group_list = api.list_repo_shared_group_by_user(USER, repo.id) assert len(group_list) == 1 group_list = api.list_repo_shared_group_by_user(USER2, repo.id) assert len(group_list) == 0 repo_get = api.get_group_shared_repo_by_path(repo.id, None, group.id) assert repo_get and repo_get.repo_id == repo.id ccnet_api.group_add_member(group.id, USER, USER2) group_list = ccnet_api.get_groups(USER2) assert len(group_list) == 1 group = group_list[0] assert group.id == group.id repos2 = api.get_repos_by_group(group.id) assert_repo_with_permission(repo, repos2, permission) assert api.check_permission(repo.id, USER2) == permission repos = api.get_group_repos_by_user(USER) assert len(repos) == 1 repoids = api.get_group_repoids(group.id) assert len(repoids) == 1 repos = api.get_group_repos_by_owner(USER) assert len(repos) == 1 api.remove_group_repos_by_owner(group.id, USER) repos = api.get_group_repos_by_owner(USER) assert len(repos) == 0 api.set_group_repo(repo.id, group.id, USER, permission) repos = api.get_repos_by_group(group.id) assert len(repos) == 1 api.remove_group_repos(group.id) repos = api.get_repos_by_group(group.id) assert len(repos) == 0 api.group_unshare_repo(repo.id, group.id, USER) repos = api.get_repos_by_group(group.id) assert len(repos) == 0 assert api.check_permission(repo.id, USER2) is None
def delete(self, request, repo_id, format=None): username = request.user.username repo = seafile_api.get_repo(repo_id) if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Library %s not found.' % repo_id) path = request.GET.get('p', '/') if seafile_api.get_dir_id_by_path(repo.id, path) is None: return api_error(status.HTTP_404_NOT_FOUND, 'Folder %s not found.' % path) if username != self.get_repo_owner(request, repo_id): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') shared_to_user, shared_to_group = self.handle_shared_to_args(request) if path == '/': shared_repo = repo else: try: sub_repo = self.get_sub_repo_by_path(request, repo, path) if sub_repo: shared_repo = sub_repo else: return api_error(status.HTTP_404_NOT_FOUND, 'Sub-library not found.') except SearpcError as e: logger.error(e) return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, 'Failed to get sub-library.') if shared_to_user: shared_to = request.GET.get('username') if shared_to is None or not is_valid_username(shared_to): return api_error(status.HTTP_400_BAD_REQUEST, 'Email %s invalid.' % shared_to) try: User.objects.get(email=shared_to) except User.DoesNotExist: return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid user, should be registered') if is_org_context(request): org_id = request.user.org.org_id seaserv.seafserv_threaded_rpc.org_remove_share( org_id, shared_repo.id, username, shared_to) else: seaserv.remove_share(shared_repo.id, username, shared_to) permission = seafile_api.check_permission_by_path(repo.id, path, shared_to) send_perm_audit_msg('delete-repo-perm', username, shared_to, repo_id, path, permission) if shared_to_group: group_id = request.GET.get('group_id') try: group_id = int(group_id) except ValueError: return api_error(status.HTTP_400_BAD_REQUEST, 'group_id %s invalid' % group_id) # hacky way to get group repo permission permission = '' for e in seafile_api.list_repo_shared_group_by_user(username, shared_repo.id): if e.group_id == group_id: permission = e.perm break if is_org_context(request): org_id = request.user.org.org_id seaserv.del_org_group_repo(shared_repo.id, org_id, group_id) else: seafile_api.unset_group_repo(shared_repo.id, group_id, username) send_perm_audit_msg('delete-repo-perm', username, group_id, repo_id, path, permission) return HttpResponse(json.dumps({'success': True}), status=200, content_type=json_content_type)
def list_lib_dir(request, repo_id): ''' New ajax API for list library directory ''' content_type = 'application/json; charset=utf-8' result = {} repo = get_repo(repo_id) if not repo: err_msg = _(u'Library does not exist.') return HttpResponse(json.dumps({'error': err_msg}), status=400, content_type=content_type) username = request.user.username path = request.GET.get('p', '/') if path[-1] != '/': path = path + '/' # perm for current dir user_perm = check_folder_permission(request, repo.id, path) if user_perm is None: err_msg = _(u'Permission denied.') return HttpResponse(json.dumps({'error': err_msg}), status=403, content_type=content_type) if repo.encrypted \ and not seafile_api.is_password_set(repo.id, username): err_msg = _(u'Library is encrypted.') return HttpResponse(json.dumps({'error': err_msg, 'lib_need_decrypt': True}), status=403, content_type=content_type) head_commit = get_commit(repo.id, repo.version, repo.head_cmmt_id) if not head_commit: err_msg = _(u'Error: no head commit id') return HttpResponse(json.dumps({'error': err_msg}), status=500, content_type=content_type) dir_list = [] file_list = [] try: dir_id = seafile_api.get_dir_id_by_path(repo.id, path) except SearpcError as e: logger.error(e) err_msg = 'Internal Server Error' return HttpResponse(json.dumps({'error': err_msg}), status=500, content_type=content_type) if not dir_id: err_msg = 'Folder not found.' return HttpResponse(json.dumps({'error': err_msg}), status=404, content_type=content_type) dirs = seafserv_threaded_rpc.list_dir_with_perm(repo_id, path, dir_id, username, -1, -1) starred_files = get_dir_starred_files(username, repo_id, path) for dirent in dirs: dirent.last_modified = dirent.mtime if stat.S_ISDIR(dirent.mode): dpath = posixpath.join(path, dirent.obj_name) if dpath[-1] != '/': dpath += '/' dir_list.append(dirent) else: if repo.version == 0: file_size = seafile_api.get_file_size(repo.store_id, repo.version, dirent.obj_id) else: file_size = dirent.size dirent.file_size = file_size if file_size else 0 dirent.starred = False fpath = posixpath.join(path, dirent.obj_name) if fpath in starred_files: dirent.starred = True file_list.append(dirent) if is_org_context(request): repo_owner = seafile_api.get_org_repo_owner(repo.id) else: repo_owner = seafile_api.get_repo_owner(repo.id) result["is_repo_owner"] = False result["has_been_shared_out"] = False if repo_owner == username: result["is_repo_owner"] = True try: if is_org_context(request): org_id = request.user.org.org_id is_inner_org_pub_repo = False # check if current repo is pub-repo org_pub_repos = seafile_api.list_org_inner_pub_repos_by_owner( org_id, username) for org_pub_repo in org_pub_repos: if repo_id == org_pub_repo.id: is_inner_org_pub_repo = True break if seafile_api.list_org_repo_shared_group(org_id, username, repo_id) or \ seafile_api.list_org_repo_shared_to(org_id, username, repo_id) or \ is_inner_org_pub_repo: result["has_been_shared_out"] = True else: if seafile_api.list_repo_shared_to(username, repo_id) or \ seafile_api.list_repo_shared_group_by_user(username, repo_id) or \ (not request.cloud_mode and seafile_api.is_inner_pub_repo(repo_id)): result["has_been_shared_out"] = True except Exception as e: logger.error(e) result["is_virtual"] = repo.is_virtual result["repo_name"] = repo.name result["user_perm"] = user_perm # check quota for fileupload result["no_quota"] = True if seaserv.check_quota(repo.id) < 0 else False result["encrypted"] = repo.encrypted dirent_list = [] for d in dir_list: d_ = {} d_['is_dir'] = True d_['obj_name'] = d.obj_name d_['last_modified'] = d.last_modified d_['last_update'] = translate_seahub_time(d.last_modified) d_['p_dpath'] = posixpath.join(path, d.obj_name) d_['perm'] = d.permission # perm for sub dir in current dir dirent_list.append(d_) size = int(request.GET.get('thumbnail_size', THUMBNAIL_DEFAULT_SIZE)) for f in file_list: f_ = {} f_['is_file'] = True f_['file_icon'] = file_icon_filter(f.obj_name) f_['obj_name'] = f.obj_name f_['last_modified'] = f.last_modified f_['last_update'] = translate_seahub_time(f.last_modified) f_['starred'] = f.starred f_['file_size'] = filesizeformat(f.file_size) f_['obj_id'] = f.obj_id f_['perm'] = f.permission # perm for file in current dir file_type, file_ext = get_file_type_and_ext(f.obj_name) if file_type == IMAGE: f_['is_img'] = True if not repo.encrypted and ENABLE_THUMBNAIL and \ os.path.exists(os.path.join(THUMBNAIL_ROOT, str(size), f.obj_id)): file_path = posixpath.join(path, f.obj_name) src = get_thumbnail_src(repo_id, size, file_path) f_['encoded_thumbnail_src'] = urlquote(src) if is_pro_version(): f_['is_locked'] = True if f.is_locked else False f_['lock_owner'] = f.lock_owner f_['lock_owner_name'] = email2nickname(f.lock_owner) if username == f.lock_owner: f_['locked_by_me'] = True else: f_['locked_by_me'] = False dirent_list.append(f_) result["dirent_list"] = dirent_list return HttpResponse(json.dumps(result), content_type=content_type)
def get(self, request, repo, path, share_type): """ List user/group shares Permission checking: 1. admin user. """ result = [] # current `request.user.username` is admin user, # so need to identify the repo owner specifically. repo_owner = seafile_api.get_repo_owner(repo.repo_id) if share_type == 'user': try: if path == '/': share_items = seafile_api.list_repo_shared_to( repo_owner, repo.repo_id) else: share_items = seafile_api.get_shared_users_for_subdir( repo.repo_id, path, repo_owner) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) admin_users = ExtraSharePermission.objects.get_admin_users_by_repo( repo.repo_id) for share_item in share_items: user_email = share_item.user user_name = email2nickname(user_email) if user_email else '--' share_info = {} share_info['repo_id'] = repo.repo_id share_info['path'] = path share_info['share_type'] = share_type share_info['user_email'] = user_email share_info['user_name'] = user_name share_info['permission'] = share_item.perm share_info['is_admin'] = user_email in admin_users result.append(share_info) if share_type == 'group': try: if path == '/': share_items = seafile_api.list_repo_shared_group_by_user( repo_owner, repo.repo_id) else: share_items = seafile_api.get_shared_groups_for_subdir( repo.repo_id, path, repo_owner) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) admin_groups = ExtraGroupsSharePermission.objects.get_admin_groups_by_repo( repo.repo_id) for share_item in share_items: group_id = share_item.group_id group = ccnet_api.get_group(group_id) group_name = group.group_name if group else '--' share_info = {} share_info['repo_id'] = repo.repo_id share_info['path'] = path share_info['share_type'] = share_type share_info['group_id'] = group_id share_info['group_name'] = group_name share_info['permission'] = share_item.perm share_info['is_admin'] = group_id in admin_groups result.append(share_info) return Response(result)
def delete(self, request, repo_id, format=None): """ Unshare a repo. Permission checking: 1. Only repo owner can unshare a library. """ # argument check share_type = request.GET.get('share_type', None) if not share_type: error_msg = 'share_type invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if share_type not in ('personal', 'group', 'public'): error_msg = "share_type can only be 'personal' or 'group' or 'public'." return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # resource check repo = seafile_api.get_repo(repo_id) if not repo: return api_error(status.HTTP_404_NOT_FOUND, 'Library %s not found.' % repo_id) # permission check username = request.user.username if is_org_context(request): repo_owner = seafile_api.get_org_repo_owner(repo_id) else: repo_owner = seafile_api.get_repo_owner(repo_id) if username != repo_owner: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # delete share org_id = None if is_org_context(request): org_id = request.user.org.org_id if share_type == 'personal': user = request.GET.get('user', None) if not user or not is_valid_username(user): error_msg = 'user invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # if user not found, permission will be None permission = seafile_api.check_permission_by_path( repo_id, '/', user) try: if org_id: seafile_api.org_remove_share(org_id, repo_id, username, user) else: seafile_api.remove_share(repo_id, username, user) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) send_perm_audit_msg('delete-repo-perm', username, user, repo_id, '/', permission) if share_type == 'group': group_id = request.GET.get('group_id', None) if not group_id: error_msg = 'group_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: group_id = int(group_id) except ValueError: error_msg = 'group_id must be integer.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # hacky way to get group repo permission permission = '' if org_id: for e in seafile_api.list_org_repo_shared_group( org_id, username, repo_id): if e.group_id == group_id: permission = e.perm break else: for e in seafile_api.list_repo_shared_group_by_user(username, repo_id): if e.group_id == group_id: permission = e.perm break try: if org_id: seaserv.del_org_group_repo(repo_id, org_id, group_id) else: seafile_api.unset_group_repo(repo_id, group_id, username) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) send_perm_audit_msg('delete-repo-perm', username, group_id, repo_id, '/', permission) if share_type == 'public': pub_repos = [] if org_id: pub_repos = seaserv.list_org_inner_pub_repos(org_id, username) if not request.cloud_mode: pub_repos = seaserv.list_inner_pub_repos(username) try: if org_id: seaserv.seafserv_threaded_rpc.unset_org_inner_pub_repo(org_id, repo_id) else: seafile_api.remove_inner_pub_repo(repo_id) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) permission = '' for repo in pub_repos: if repo.repo_id == repo_id: permission = repo.permission break if permission: send_perm_audit_msg('delete-repo-perm', username, 'all', repo_id, '/', permission) return Response({'success': True})
def put(self, request, repo_id, format=None): """ transfer a library Permission checking: 1. only admin can perform this action. """ repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) new_owner = request.data.get('owner', None) if not new_owner: error_msg = 'owner invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: User.objects.get(email=new_owner) except User.DoesNotExist: error_msg = 'User %s not found.' % new_owner return api_error(status.HTTP_404_NOT_FOUND, error_msg) if MULTI_TENANCY: try: if seafserv_threaded_rpc.get_org_id_by_repo_id(repo_id) > 0: error_msg = 'Can not transfer organization library.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if ccnet_api.get_orgs_by_user(new_owner): error_msg = 'Can not transfer library to organization user %s' % new_owner return api_error(status.HTTP_403_FORBIDDEN, error_msg) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) repo_owner = seafile_api.get_repo_owner(repo_id) # get repo shared to user/group list shared_users = seafile_api.list_repo_shared_to( repo_owner, repo_id) shared_groups = seafile_api.list_repo_shared_group_by_user( repo_owner, repo_id) # get all pub repos pub_repos = [] if not request.cloud_mode: pub_repos = seafile_api.list_inner_pub_repos_by_owner(repo_owner) # transfer repo seafile_api.set_repo_owner(repo_id, new_owner) # reshare repo to user for shared_user in shared_users: shared_username = shared_user.user if new_owner == shared_username: continue seafile_api.share_repo(repo_id, new_owner, shared_username, shared_user.perm) # reshare repo to group for shared_group in shared_groups: shared_group_id = shared_group.group_id if not ccnet_api.is_group_user(shared_group_id, new_owner): continue seafile_api.set_group_repo(repo_id, shared_group_id, new_owner, shared_group.perm) # check if current repo is pub-repo # if YES, reshare current repo to public for pub_repo in pub_repos: if repo_id != pub_repo.id: continue seafile_api.add_inner_pub_repo(repo_id, pub_repo.permission) break repo = seafile_api.get_repo(repo_id) repo_info = get_repo_info(repo) return Response(repo_info)
def put(self, request, repo_id, format=None): """ transfer a library, rename a library Permission checking: 1. only admin can perform this action. """ repo = seafile_api.get_repo(repo_id) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) new_repo_name = request.data.get('name', None) if new_repo_name: try: res = seafile_api.edit_repo(repo_id, new_repo_name, '', None) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if res == -1: e = 'Admin rename failed: ID of library is %s, edit_repo api called failed.' % \ repo_id logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) new_owner = request.data.get('owner', None) if new_owner: try: new_owner_obj = User.objects.get(email=new_owner) except User.DoesNotExist: error_msg = 'User %s not found.' % new_owner return api_error(status.HTTP_404_NOT_FOUND, error_msg) if not new_owner_obj.permissions.can_add_repo(): error_msg = _(u'Transfer failed: role of %s is %s, can not add library.') % \ (new_owner, new_owner_obj.role) return api_error(status.HTTP_403_FORBIDDEN, error_msg) if MULTI_TENANCY: try: if seafile_api.get_org_id_by_repo_id(repo_id) > 0: error_msg = 'Can not transfer organization library.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if ccnet_api.get_orgs_by_user(new_owner): error_msg = 'Can not transfer library to organization user %s' % new_owner return api_error(status.HTTP_403_FORBIDDEN, error_msg) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) repo_owner = seafile_api.get_repo_owner(repo_id) if new_owner == repo_owner: error_msg = _(u"Library can not be transferred to owner.") return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # get repo shared to user/group list shared_users = seafile_api.list_repo_shared_to( repo_owner, repo_id) shared_groups = seafile_api.list_repo_shared_group_by_user( repo_owner, repo_id) # get all pub repos pub_repos = [] if not request.cloud_mode: pub_repos = seafile_api.list_inner_pub_repos_by_owner(repo_owner) # transfer repo seafile_api.set_repo_owner(repo_id, new_owner) # reshare repo to user for shared_user in shared_users: shared_username = shared_user.user if new_owner == shared_username: continue seafile_api.share_repo(repo_id, new_owner, shared_username, shared_user.perm) # reshare repo to group for shared_group in shared_groups: shared_group_id = shared_group.group_id if not is_group_member(shared_group_id, new_owner): continue seafile_api.set_group_repo(repo_id, shared_group_id, new_owner, shared_group.perm) # reshare repo to links try: UploadLinkShare.objects.filter(username=repo_owner, repo_id=repo_id).update(username=new_owner) FileShare.objects.filter(username=repo_owner, repo_id=repo_id).update(username=new_owner) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) # check if current repo is pub-repo # if YES, reshare current repo to public for pub_repo in pub_repos: if repo_id != pub_repo.id: continue seafile_api.add_inner_pub_repo(repo_id, pub_repo.permission) break # send admin operation log signal admin_op_detail = { "id": repo_id, "name": repo.name, "from": repo_owner, "to": new_owner, } admin_operation.send(sender=None, admin_name=request.user.username, operation=REPO_TRANSFER, detail=admin_op_detail) repo = seafile_api.get_repo(repo_id) repo_info = get_repo_info(repo) return Response(repo_info)