def get_group_repos(username, org_id, groups): """Get repos shared to groups. """ group_repos = [] if org_id: # For each group I joined... for grp in groups: # Get group repos, and for each group repos... for r_id in seafile_api.get_org_group_repoids(org_id, grp.id): # No need to list my own repo repo_owner = seafile_api.get_org_repo_owner(r_id) if repo_owner == username: continue # Convert repo properties due to the different collumns in Repo # and SharedRepo r = seafile_api.get_repo(r_id) if not r: continue r.repo_id = r.id r.repo_name = r.name r.repo_desc = r.desc r.last_modified = get_repo_last_modify(r) r.share_type = 'group' r.user = repo_owner r.user_perm = seafile_api.check_repo_access_permission( r_id, username) r.group = grp group_repos.append(r) else: # For each group I joined... for grp in groups: # Get group repos, and for each group repos... for r_id in seafile_api.get_group_repoids(grp.id): # No need to list my own repo repo_owner = seafile_api.get_repo_owner(r_id) if repo_owner == username: continue # Convert repo properties due to the different collumns in Repo # and SharedRepo r = seafile_api.get_repo(r_id) if not r: continue r.repo_id = r.id r.repo_name = r.name r.repo_desc = r.desc r.last_modified = get_repo_last_modify(r) r.share_type = 'group' r.user = repo_owner r.user_perm = seafile_api.check_repo_access_permission( r_id, username) r.group = grp group_repos.append(r) return group_repos
def list_shared_links(request): """List shared links, and remove invalid links(file/dir is deleted or moved). """ username = request.user.username # download links fileshares = FileShare.objects.filter(username=username) p_fileshares = [] # personal file share for fs in fileshares: if is_personal_repo(fs.repo_id): # only list files in personal repos r = seafile_api.get_repo(fs.repo_id) if not r: fs.delete() continue if fs.s_type == 'f': if seafile_api.get_file_id_by_path(r.id, fs.path) is None: fs.delete() continue fs.filename = os.path.basename(fs.path) fs.shared_link = gen_file_share_link(fs.token) else: if seafile_api.get_dir_id_by_path(r.id, fs.path) is None: fs.delete() continue fs.filename = os.path.basename(fs.path.rstrip('/')) fs.shared_link = gen_dir_share_link(fs.token) fs.repo = r p_fileshares.append(fs) # upload links uploadlinks = UploadLinkShare.objects.filter(username=username) p_uploadlinks = [] for link in uploadlinks: if is_personal_repo(link.repo_id): r = seafile_api.get_repo(link.repo_id) if not r: link.delete() continue if seafile_api.get_dir_id_by_path(r.id, link.path) is None: link.delete() continue link.dir_name = os.path.basename(link.path.rstrip('/')) link.shared_link = gen_shared_upload_link(link.token) link.repo = r p_uploadlinks.append(link) return render_to_response('share/links.html', { "fileshares": p_fileshares, "uploadlinks": p_uploadlinks, }, context_instance=RequestContext(request))
def put(self, request, repo_id): """ Copy a single file/folder to other place. """ # check parameter for src path = request.GET.get('path', None) if not path: error_msg = 'path invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: dirent = seafile_api.get_dirent_by_path(repo_id, path) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if not dirent: error_msg = 'File or folder %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) if path == '/': error_msg = 'path invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # normalize path to '/1/2/3' format # NOT ends with '/' path = normalize_file_path(path) # now get `src_dir` and `obj_name` according to normalized path src_repo_id = repo_id src_dir = os.path.dirname(path) src_obj_name = os.path.basename(path) # check parameter for dst dst_repo_id = request.data.get('dst_repo_id', src_repo_id) if dst_repo_id != src_repo_id and not seafile_api.get_repo(dst_repo_id): error_msg = 'Library %s not found.' % dst_repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) dst_dir = request.data.get('dst_dir', '/') if dst_dir != '/': dst_dir = normalize_dir_path(dst_dir) if not seafile_api.get_dir_id_by_path(dst_repo_id, dst_dir): error_msg = 'Folder %s not found.' % dst_dir return api_error(status.HTTP_404_NOT_FOUND, error_msg) # copy file username = request.user.username dst_obj_name = check_filename_with_rename(dst_repo_id, dst_dir, src_obj_name) try: seafile_api.copy_file(src_repo_id, src_dir, src_obj_name, dst_repo_id, dst_dir, dst_obj_name, username, need_progress=0, synchronous=1) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return Response({'success': True, 'dst_item_name': dst_obj_name})
def _get_upload_link_info(self, uls): data = {} token = uls.token repo_id = uls.repo_id try: repo = seafile_api.get_repo(repo_id) except Exception as e: logger.error(e) repo = None path = uls.path if path: obj_name = '/' if path == '/' else os.path.basename(path.rstrip('/')) else: obj_name = '' if uls.ctime: ctime = datetime_to_isoformat_timestr(uls.ctime) else: ctime = '' data['repo_id'] = repo_id data['repo_name'] = repo.repo_name if repo else '' data['path'] = path data['obj_name'] = obj_name data['view_cnt'] = uls.view_cnt data['ctime'] = ctime data['link'] = gen_shared_upload_link(token) data['token'] = token data['username'] = uls.username return data
def get(self, request, repo_id, format=None): """ Get all file/folder in a library """ repo = seafile_api.get_repo(repo_id) parent_dir = request.GET.get('parent_dir', '/') parent_dir = normalize_dir_path(parent_dir) dir_id = seafile_api.get_dir_id_by_path(repo_id, parent_dir) if not dir_id: error_msg = 'Folder %s not found.' % parent_dir return api_error(status.HTTP_404_NOT_FOUND, error_msg) repo_owner = get_repo_owner(request, repo_id) try: dirs = seafile_api.list_dir_with_perm(repo_id, parent_dir, dir_id, repo_owner, -1, -1) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return_results = {} return_results['repo_name'] = repo.repo_name return_results['repo_id'] = repo.repo_id return_results['is_system_library'] = True if \ repo.id == get_system_default_repo_id() else False return_results['dirent_list'] = [] for dirent in dirs: dirent_info = get_dirent_info(dirent) return_results['dirent_list'].append(dirent_info) return Response(return_results)
def post(self, request, org_id, format=None): """Create a file draft if the user has read-write permission to the origin file """ repo_id = request.POST.get('repo_id', '') file_path = request.POST.get('file_path', '') 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) # perm check perm = check_folder_permission(request, repo.id, file_path) if perm != PERMISSION_READ_WRITE: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) file_id = seafile_api.get_file_id_by_path(repo.id, file_path) if not file_id: return api_error(status.HTTP_404_NOT_FOUND, "File %s not found" % file_path) username = request.user.username try: d = Draft.objects.add(username, repo, file_path, file_id) return Response(d.to_dict()) except DraftFileExist: return api_error(status.HTTP_409_CONFLICT, 'Draft already exists.') except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
def format_file_comment_msg(self): try: d = json.loads(self.detail) except Exception as e: logger.error(e) return _(u"Internal error") repo_id = d['repo_id'] file_path = d['file_path'] author = d['author'] comment = d['comment'] repo = seafile_api.get_repo(repo_id) if repo is None or not seafile_api.get_file_id_by_path(repo.id, file_path): self.delete() return None file_name = os.path.basename(file_path) msg = _("File <a href='%(file_url)s'>%(file_name)s</a> has a new comment from user %(author)s") % { 'file_url': reverse('view_lib_file', args=[repo_id, file_path]), 'file_name': escape(file_name), 'author': escape(email2nickname(author)), } return msg
def format_repo_share_msg(self): """ Arguments: - `self`: """ try: d = json.loads(self.detail) except Exception as e: logger.error(e) return _(u"Internal error") share_from = email2nickname(d['share_from']) repo_id = d['repo_id'] repo = seafile_api.get_repo(repo_id) if repo is None: self.delete() return None msg = _(u"%(user)s has shared a library named <a href='%(href)s'>%(repo_name)s</a> to you.") % { 'user': escape(share_from), 'href': reverse('view_common_lib_dir', args=[repo.id, '']), 'repo_name': escape(repo.name), } return msg
def get(self, request): if not is_pro_version(): error_msg = 'Feature disabled.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # check the date format, should be like '2015-10-10' start = request.GET.get('start', None) end = request.GET.get('end', None) if not check_time_period_valid(start, end): error_msg = 'start or end date invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) result = [] events = get_log_events_by_type_and_time('file_audit', start, end) if events: for ev in events: tmp_repo = seafile_api.get_repo(ev.repo_id) tmp_repo_name = tmp_repo.name if tmp_repo else '' result.append({ 'repo_id': ev.repo_id, 'repo_name': tmp_repo_name, 'time': datetime_to_isoformat_timestr(ev.timestamp), 'etype': ev.etype, 'ip': ev.ip, 'file_path': ev.file_path, 'etype': ev.etype, 'user_name': email2nickname(ev.user), 'user_email': ev.user }) return Response(result)
def personal_wiki_use_lib(request): if request.method != 'POST': raise Http404 repo_id = request.POST.get('dst_repo', '') username = request.user.username next = reverse('personal_wiki', args=[]) repo = seafile_api.get_repo(repo_id) if repo is None: messages.error(request, _('Failed to set wiki library.')) return HttpResponseRedirect(next) if check_folder_permission(request, repo_id, '/') != 'rw': messages.error(request, _('Permission denied.')) return HttpResponseRedirect(next) PersonalWiki.objects.save_personal_wiki(username=username, repo_id=repo_id) # create home page if not exist page_name = "home.md" if not seaserv.get_file_id_by_path(repo_id, "/" + page_name): if not seaserv.post_empty_file(repo_id, "/", page_name, username): messages.error(request, _('Failed to create home page. Please retry later')) return HttpResponseRedirect(next)
def post(self, request, repo_id): 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) password = request.POST.get("password", None) if not password: error_msg = "password invalid." return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: seafile_api.set_passwd(repo_id, request.user.username, password) return Response({"success": True}) except SearpcError as e: if e.msg == "Bad arguments": error_msg = "Bad arguments" return api_error(status.HTTP_400_BAD_REQUEST, error_msg) elif e.msg == "Incorrect password": error_msg = _(u"Wrong password") return api_error(status.HTTP_400_BAD_REQUEST, error_msg) elif e.msg == "Internal server error": error_msg = _(u"Internal server error") return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) else: error_msg = _(u"Decrypt library error") return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
def add(self, wiki_name, username, permission='private', repo_id=None, org_id=-1): if not permission: permission = 'private' from .utils import slugfy_wiki_name slug = slugfy_wiki_name(wiki_name) if self.filter(slug=slug).count() > 0: raise DuplicateWikiNameError now = timezone.now() if repo_id is None: # create new repo to store the wiki pages if org_id > 0: repo_id = seafile_api.create_org_repo(wiki_name, '', username, passwd=None, org_id=org_id) else: repo_id = seafile_api.create_repo(wiki_name, '', username, passwd=None) repo = seafile_api.get_repo(repo_id) assert repo is not None wiki = self.model(username=username, name=wiki_name, slug=slug, repo_id=repo.id, permission=permission, created_at=now) wiki.save(using=self._db) return wiki
def _decorated(view, request, *args, **kwargs): # argument check if request.method == 'GET': repo_id = request.GET.get('repo_id', None) path = request.GET.get('path', '/') share_type = request.GET.get('share_type', None) else: repo_id = request.data.get('repo_id', None) path = request.data.get('path', '/') share_type = request.data.get('share_type', None) if not repo_id: error_msg = 'repo_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if not share_type or share_type not in ('user', 'group'): error_msg = 'share_type 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 not seafile_api.get_dir_id_by_path(repo_id, path): error_msg = 'Folder %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) return func(view, request, repo, path, share_type, *args, **kwargs)
def delete(self, request, repo_id, file_tag_id): """delete a tag from a file """ # 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) file_tag = FileTags.objects.get_file_tag_by_id(file_tag_id) if not file_tag: error_msg = 'file_tag %s not found.' % file_tag_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check if check_folder_permission(request, repo_id, '/') != PERMISSION_READ_WRITE: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: FileTags.objects.delete_file_tag(file_tag_id) except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return Response({"success": "true"}, status=status.HTTP_200_OK)
def format_repo_share_msg(self, notice): d = json.loads(notice.detail) repo_id = d['repo_id'] repo = seafile_api.get_repo(repo_id) path = d['path'] org_id = d.get('org_id', None) if path == '/': shared_type = 'library' else: shared_type = 'folder' if org_id: owner = seafile_api.get_org_repo_owner(repo_id) repo = seafile_api.get_org_virtual_repo( org_id, repo_id, path, owner) else: owner = seafile_api.get_repo_owner(repo_id) repo = seafile_api.get_virtual_repo(repo_id, path, owner) repo_url = reverse('lib_view', args=[repo_id, repo.name, '']) notice.repo_url = repo_url notice.notice_from = escape(email2nickname(d['share_from'])) notice.repo_name = repo.name notice.avatar_src = self.get_avatar_src(d['share_from']) notice.shared_type = shared_type return notice
def edit_profile(request): """ Show and edit user profile. """ username = request.user.username form_class = DetailedProfileForm if request.method == 'POST': form = form_class(request.POST) if form.is_valid(): form.save(username=username) messages.success(request, _(u'Successfully edited profile.')) return HttpResponseRedirect(reverse('edit_profile')) else: messages.error(request, _(u'Failed to edit profile')) else: profile = Profile.objects.get_profile_by_user(username) d_profile = DetailedProfile.objects.get_detailed_profile_by_user( username) init_dict = {} if profile: init_dict['nickname'] = profile.nickname init_dict['login_id'] = profile.login_id init_dict['contact_email'] = profile.contact_email if d_profile: init_dict['department'] = d_profile.department init_dict['telephone'] = d_profile.telephone form = form_class(init_dict) # common logic try: server_crypto = UserOptions.objects.is_server_crypto(username) except CryptoOptionNotSetError: # Assume server_crypto is ``False`` if this option is not set. server_crypto = False sub_lib_enabled = UserOptions.objects.is_sub_lib_enabled(username) default_repo_id = UserOptions.objects.get_default_repo(username) if default_repo_id: default_repo = seafile_api.get_repo(default_repo_id) else: default_repo = None owned_repos = get_owned_repo_list(request) owned_repos = filter(lambda r: not r.is_virtual, owned_repos) return render_to_response('profile/set_profile.html', { 'form': form, 'server_crypto': server_crypto, "sub_lib_enabled": sub_lib_enabled, 'force_server_crypto': settings.FORCE_SERVER_CRYPTO, 'default_repo': default_repo, 'owned_repos': owned_repos, 'is_pro': is_pro_version(), 'is_ldap_user': is_ldap_user(request.user), 'two_factor_auth_enabled': has_two_factor_auth(), }, context_instance=RequestContext(request))
def delete(self, request, slug, page_name): """Delete a page in a wiki """ try: wiki = Wiki.objects.get(slug=slug) except Wiki.DoesNotExist: error_msg = "Wiki not found." return api_error(status.HTTP_404_NOT_FOUND, error_msg) username = request.user.username if wiki.username != username: error_msg = _('Permission denied.') return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: repo = seafile_api.get_repo(wiki.repo_id) if not repo: error_msg = "Wiki library not found." return api_error(status.HTTP_404_NOT_FOUND, error_msg) except SearpcError: error_msg = _("Internal Server Error") return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) file_name = page_name + ".md" try: seafile_api.del_file(repo.id, '/', file_name, request.user.username) except SearpcError as e: logger.error(e) error_msg = _('Internal Server Error') return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return Response()
def check_group_folder_perm_args(from_user, repo_id, path, group_id, perm = None): if not seafile_api.get_repo(repo_id): return {'error': _(u'Library does not exist.'), 'status': 400} if check_repo_access_permission(repo_id, from_user) != 'rw': return {'error': _('Permission denied'), 'status': 403} if perm is not None: # add or toggle folder perm if seafile_api.get_dir_id_by_path(repo_id, path) is None: return {'error': _('Invalid path'), 'status': 400} if perm != 'r' and perm != 'rw': return {'error': _('Invalid folder permission'), 'status': 400} if not path.startswith('/'): return {'error': _('Path should start with "/"'), 'status': 400} if path != '/' and path.endswith('/'): return {'error': _('Path should NOT ends with "/"'), 'status': 400} if not seaserv.get_group(group_id): return {'error': _('Invalid group'), 'status': 400} return {'success': True}
def check_user_folder_perm_args(from_user, repo_id, path, to_user, perm=None): if not seafile_api.get_repo(repo_id): return {'error': _(u'Library does not exist.'), 'status': 400} if check_repo_access_permission(repo_id, from_user) != 'rw': return {'error': _('Permission denied'), 'status': 403} if perm is not None: # add or toggle folder perm if seafile_api.get_dir_id_by_path(repo_id, path) is None: return {'error': _('Invalid path'), 'status': 400} if perm != 'r' and perm != 'rw': return {'error': _('Invalid folder permission'), 'status': 400} if not path.startswith('/'): return {'error': _('Path should start with "/"'), 'status': 400} if path != '/' and path.endswith('/'): return {'error': _('Path should NOT ends with "/"'), 'status': 400} try: user = User.objects.get(email = to_user) except User.DoesNotExist: user = None if user is None: return {'error': _('Invalid username, should be a user already registered'), 'status': 400} return {'success': True}
def format_file_uploaded_msg(self): """ Arguments: - `self`: """ d = json.loads(self.detail) filename = d['file_name'] repo_id = d['repo_id'] if d['uploaded_to'] == '/': # current upload path is '/' file_path = '/' + filename link = reverse('view_common_lib_dir', args=[repo_id, '']) name = seafile_api.get_repo(repo_id).name else: uploaded_to = d['uploaded_to'].rstrip('/') file_path = uploaded_to + '/' + filename link = reverse('view_common_lib_dir', args=[repo_id, urlquote(uploaded_to.lstrip('/'))]) name = os.path.basename(uploaded_to) file_link = reverse('view_lib_file', args=[repo_id, urlquote(file_path)]) msg = _(u"A file named <a href='%(file_link)s'>%(file_name)s</a> is uploaded to <a href='%(link)s'>%(name)s</a>") % { 'file_link': file_link, 'file_name': escape(filename), 'link': link, 'name': escape(name), } return msg
def setUp(self): self.login_as(self.admin) # create group for admin user self.admin_group_1_name = randstring(6) self.admin_group_1_id = ccnet_threaded_rpc.create_group(self.admin_group_1_name, self.admin.email) # create another group for admin user self.admin_group_2_name = randstring(6) self.admin_group_2_id = ccnet_threaded_rpc.create_group(self.admin_group_2_name, self.admin.email) # create repo for admin user self.admin_repo_name = randstring(6) r = seafile_api.get_repo(self.create_repo(name=self.admin_repo_name, desc='', username=self.admin.email, passwd=None)) self.admin_repo_id = r.id # set common user as staff in admin user's group ccnet_threaded_rpc.group_add_member(self.admin_group_1_id, self.admin.email, self.user.email) ccnet_threaded_rpc.group_set_admin(self.admin_group_1_id, self.user.email) # add common user to admin user's another group ccnet_threaded_rpc.group_add_member(self.admin_group_2_id, self.admin.email, self.user.email) # share admin user's repo to common user seafile_api.share_repo(self.admin_repo_id, self.admin.email, self.user.email, 'rw')
def get_file_revisions_after_renamed(repo_id, path): all_file_revisions = [] repo = seafile_api.get_repo(repo_id) commit_id = repo.head_cmmt_id start_time = time.time() keep_on_search = True while keep_on_search: file_revisions = seafile_api.get_file_revisions(repo_id, commit_id, path, 50) all_file_revisions += file_revisions[0:-1] end_time = time.time() next_start_commit = file_revisions[-1].next_start_commit rev_renamed_old_path = file_revisions[-2].rev_renamed_old_path if \ len(file_revisions) > 1 else None if not next_start_commit or \ rev_renamed_old_path or \ end_time - start_time > GET_FILE_HISTORY_TIMEOUT: # have searched all commits or # found a file renamed/moved commit or # timeout keep_on_search = False else: # keep on searching, use next_start_commit # as the commit_id start to search commit_id = next_start_commit return all_file_revisions
def get(self, request, repo_id): """ List repo user share info. Permission checking: 1. is group admin """ # 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) repo_owner = get_repo_owner(request, repo_id) group_id = get_group_id_by_repo_owner(repo_owner) if not ccnet_api.get_group(group_id): error_msg = 'Group %s not found.' % group_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) path = request.GET.get('path', '/') if not seafile_api.get_dir_id_by_path(repo_id, path): error_msg = 'Folder %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check username = request.user.username if not is_group_admin(group_id, username): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) result = self.list_user_shared_items(request, repo_id, path) return Response(result)
def delete(self, request, repo_id, org_id, format=None): """ User delete a repo shared to him/her. """ 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 not check_folder_permission(request, repo_id, '/'): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) username = request.user.username repo_owner = get_repo_owner(request, repo_id) try: if org_id: is_org = True seafile_api.org_remove_share(org_id, repo_id, repo_owner, username) else: is_org = False seafile_api.remove_share(repo_id, repo_owner, username) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) permission = check_user_share_in_permission(repo_id, username, is_org) send_perm_audit_msg('delete-repo-perm', repo_owner, username, repo_id, '/', permission) return Response({'success': True})
def delete(self, request, group_id, repo_id, org_id): """ Delete a group owned library. Permission checking: 1. is group admin; """ 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) group_id = int(group_id) username = request.user.username if not is_group_admin(group_id, username): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: SeafileAPI.delete_group_owned_repo(group_id, repo_id, org_id) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return Response({'success': True})
def get(self, request, repo_id): """list all tags of a file. """ # argument check file_path = request.GET.get('file_path') if not file_path: error_msg = 'file_path invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) file_path = normalize_file_path(file_path) # 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) file_id = seafile_api.get_file_id_by_path(repo_id, file_path) if not file_id: error_msg = 'File not found.' return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check if not check_folder_permission(request, repo_id, '/'): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: file_tags = FileTags.objects.get_file_tag_by_path(repo_id, file_path) except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return Response({"file_tags": file_tags}, status=status.HTTP_200_OK)
def delete(self, request, repo_id, format=None): # delete file 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) path = request.GET.get('p', None) if not path: error_msg = 'p invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) file_id = seafile_api.get_file_id_by_path(repo_id, path) if not file_id: return Response({'success': True}) parent_dir = os.path.dirname(path) if check_folder_permission(request, repo_id, parent_dir) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) parent_dir = os.path.dirname(path) file_name = os.path.basename(path) try: seafile_api.del_file(repo_id, parent_dir, file_name, request.user.username) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if request.GET.get('reloaddir', '').lower() == 'true': return reloaddir(request, repo, parent_dir) else: return Response({'success': True})
def repo_restored_cb(sender, **kwargs): repo_id = kwargs['repo_id'] operator = kwargs['operator'] repo = seafile_api.get_repo(repo_id) org_id = get_org_id_by_repo_id(repo_id) if org_id > 0: related_users = seafile_api.org_get_shared_users_by_repo(org_id, repo_id) repo_owner = seafile_api.get_org_repo_owner(repo_id) else: related_users = seafile_api.get_shared_users_by_repo(repo_id) repo_owner = seafile_api.get_repo_owner(repo_id) related_users.append(repo_owner) record = { 'op_type':'recover', 'obj_type':'repo', 'timestamp': datetime.datetime.utcnow(), 'repo_id': repo_id, 'repo_name': repo.repo_name, 'path': '/', 'op_user': operator, 'related_users': [related_users], 'org_id': org_id, } from utils import SeafEventsSession session = SeafEventsSession() seafevents.save_user_activity(session, record) session.close()
def get_all_file_revisions(repo_id, path, commit_id=None): """ Only used for test revert file. py.test tests/api/endpoints/test_file_view.py::FileViewTest::test_can_revert_file """ all_file_revisions = [] if not commit_id: repo = seafile_api.get_repo(repo_id) commit_id = repo.head_cmmt_id file_revisions = seafile_api.get_file_revisions(repo_id, commit_id, path, -1) all_file_revisions += file_revisions # if commit's rev_renamed_old_path value not None, seafile will stop searching. # so always uses `rev_renamed_old_path` info. next_start_commit = file_revisions[-1].next_start_commit if next_start_commit: path = file_revisions[-2].rev_renamed_old_path if \ len(file_revisions) > 1 else None file_revisions = get_all_file_revisions(repo_id, path, next_start_commit) all_file_revisions += file_revisions # from seafile_api: # @next_start_commit: commit_id for next page. # An extra commit which only contains @next_start_commit will be appended to the list. return all_file_revisions[0:-1]
def get_file_info(self, username, repo_id, file_path): repo = seafile_api.get_repo(repo_id) file_obj = seafile_api.get_dirent_by_path(repo_id, file_path) file_name = file_obj.obj_name file_size = file_obj.size can_preview, error_msg = can_preview_file(file_name, file_size, repo) can_edit, error_msg = can_edit_file(file_name, file_size, repo) try: is_locked, locked_by_me = check_file_lock(repo_id, file_path, username) except Exception as e: logger.error(e) is_locked = False file_info = { 'type': 'file', 'repo_id': repo_id, 'parent_dir': os.path.dirname(file_path), 'obj_name': file_name, 'obj_id': file_obj.obj_id, 'size': file_size, 'mtime': timestamp_to_isoformat_timestr(file_obj.mtime), 'is_locked': is_locked, 'can_preview': can_preview, 'can_edit': can_edit, } return file_info
def post(self, request): """ Create share link. Permission checking: 1. default(NOT guest) user; """ # argument check repo_id = request.data.get('repo_id', None) if not repo_id: error_msg = 'repo_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) path = request.data.get('path', None) if not path: error_msg = 'path invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) password = request.data.get('password', None) if password and len(password) < config.SHARE_LINK_PASSWORD_MIN_LENGTH: error_msg = _('Password is too short.') return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: expire_days = int(request.data.get('expire_days', 0)) except ValueError: error_msg = 'expire_days invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if expire_days <= 0: if SHARE_LINK_EXPIRE_DAYS_DEFAULT > 0: expire_days = SHARE_LINK_EXPIRE_DAYS_DEFAULT if SHARE_LINK_EXPIRE_DAYS_MIN > 0: if expire_days < SHARE_LINK_EXPIRE_DAYS_MIN: error_msg = _('Expire days should be greater or equal to %s') % \ SHARE_LINK_EXPIRE_DAYS_MIN return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if SHARE_LINK_EXPIRE_DAYS_MAX > 0: if expire_days > SHARE_LINK_EXPIRE_DAYS_MAX: error_msg = _('Expire days should be less than or equal to %s') % \ SHARE_LINK_EXPIRE_DAYS_MAX return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if expire_days <= 0: expire_date = None else: expire_date = timezone.now() + relativedelta(days=expire_days) try: perm = check_permissions_arg(request) except Exception: error_msg = 'permissions 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 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: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) username = request.user.username repo_folder_permission = seafile_api.check_permission_by_path( repo_id, path, username) if parse_repo_perm( repo_folder_permission).can_generate_share_link is False: 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 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, error_msg = 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 if s_type == 'f': fs = FileShare.objects.get_file_link_by_path( username, repo_id, path) if fs: error_msg = _('Share link %s already exists.' % fs.token) return api_error(status.HTTP_400_BAD_REQUEST, error_msg) fs = FileShare.objects.create_file_link(username, repo_id, path, password, expire_date, permission=perm, org_id=org_id) elif s_type == 'd': fs = FileShare.objects.get_dir_link_by_path( username, repo_id, path) if fs: error_msg = _('Share link %s already exists.' % fs.token) return api_error(status.HTTP_400_BAD_REQUEST, error_msg) fs = FileShare.objects.create_dir_link(username, repo_id, path, password, expire_date, permission=perm, org_id=org_id) link_info = get_share_link_info(fs) return Response(link_info)
def post(self, request, repo_id, format=None): """ Create, rename, move, copy file Permission checking: 1. create: user with 'rw' permission for current parent dir; 2. rename: user with 'rw' permission for current file; 3. move : user with 'rw' permission for current file, 'rw' permission for dst parent dir; 4. copy : user with 'r' permission for current file, 'rw' permission for dst parent dir; """ # argument check path = request.GET.get('p', None) if not path or path[0] != '/': error_msg = 'p invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) operation = request.data.get('operation', None) if not operation: error_msg = 'operation invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) operation = operation.lower() if operation not in ('create', 'rename', 'move', 'copy'): error_msg = "operation can only be 'create', 'rename', 'move' or 'copy'." 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) username = request.user.username parent_dir = os.path.dirname(path) if operation == 'create': # resource check try: parent_dir_id = seafile_api.get_dir_id_by_path( repo_id, parent_dir) 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 parent_dir_id: error_msg = 'Folder %s not found.' % parent_dir return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check if check_folder_permission(request, repo_id, parent_dir) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # create file new_file_name = os.path.basename(path) new_file_name = check_filename_with_rename(repo_id, parent_dir, new_file_name) try: seafile_api.post_empty_file(repo_id, parent_dir, new_file_name, username) except SearpcError, e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) new_file_path = posixpath.join(parent_dir, new_file_name) file_info = self.get_file_info(username, repo_id, new_file_path) return Response(file_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)
def delete(self, request, repo_id, format=None): """ delete a library Permission checking: 1. only admin can perform this action. """ if get_system_default_repo_id() == repo_id: error_msg = _('System library can not be deleted.') return api_error(status.HTTP_400_BAD_REQUEST, error_msg) repo = seafile_api.get_repo(repo_id) if not repo: # for case of `seafile-data` has been damaged # no `repo object` will be returned from seafile api # delete the database record anyway try: seafile_api.remove_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) return Response({'success': True}) repo_name = repo.name repo_owner = seafile_api.get_repo_owner(repo_id) if not repo_owner: repo_owner = seafile_api.get_org_repo_owner(repo_id) try: seafile_api.remove_repo(repo_id) try: org_id = seafile_api.get_org_id_by_repo_id(repo_id) related_usernames = get_related_users_by_repo( repo_id, org_id if org_id > 0 else None) except Exception as e: logger.error(e) org_id = -1 related_usernames = [] # send signal for seafevents repo_deleted.send(sender=None, org_id=-1, operator=request.user.username, usernames=related_usernames, repo_owner=repo_owner, repo_id=repo_id, repo_name=repo.name) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) # send admin operation log signal admin_op_detail = { "id": repo_id, "name": repo_name, "owner": repo_owner, } admin_operation.send(sender=None, admin_name=request.user.username, operation=REPO_DELETE, detail=admin_op_detail) return Response({'success': True})
def get_onlyoffice_dict(request, username, repo_id, file_path, file_id='', can_edit=False, can_download=True): repo = seafile_api.get_repo(repo_id) if repo.is_virtual: origin_repo_id = repo.origin_repo_id origin_file_path = posixpath.join(repo.origin_path, file_path.strip('/')) # for view history/trash/snapshot file if not file_id: file_id = seafile_api.get_file_id_by_path(origin_repo_id, origin_file_path) else: origin_repo_id = repo_id origin_file_path = file_path if not file_id: file_id = seafile_api.get_file_id_by_path(repo_id, file_path) dl_token = seafile_api.get_fileserver_access_token(repo_id, file_id, 'download', username, use_onetime=True) if not dl_token: return None filetype, fileext = get_file_type_and_ext(file_path) if fileext in ('xls', 'xlsx', 'ods', 'fods', 'csv'): document_type = 'spreadsheet' elif fileext in ('pptx', 'ppt', 'odp', 'fodp', 'ppsx', 'pps'): document_type = 'presentation' else: document_type = 'text' cache_key = generate_onlyoffice_cache_key(repo_id, file_path) doc_key = cache.get(cache_key) # temporary solution when failed to get data from cache(django_pylibmc) # when init process for the first time if not doc_key: doc_key = cache.get(cache_key) if not doc_key and if_locked_by_online_office(repo_id, file_path): logger.error('no doc_key in cache and locked by online office') if not doc_key: info_bytes = force_bytes(origin_repo_id + origin_file_path + file_id) doc_key = hashlib.md5(info_bytes).hexdigest()[:20] doc_info = json.dumps({ 'repo_id': repo_id, 'file_path': file_path, 'username': username }) cache.set("ONLYOFFICE_%s" % doc_key, doc_info, None) file_name = os.path.basename(file_path.rstrip('/')) doc_url = gen_file_get_url(dl_token, file_name) base_url = get_site_scheme_and_netloc() onlyoffice_editor_callback_url = reverse('onlyoffice_editor_callback') callback_url = urllib.parse.urljoin(base_url, onlyoffice_editor_callback_url) return_dict = { 'repo_id': repo_id, 'path': file_path, 'ONLYOFFICE_APIJS_URL': ONLYOFFICE_APIJS_URL, 'file_type': fileext, 'doc_key': doc_key, 'doc_title': file_name, 'doc_url': doc_url, 'document_type': document_type, 'callback_url': callback_url, 'can_edit': can_edit, 'can_download': can_download, 'username': username, 'onlyoffice_force_save': ONLYOFFICE_FORCE_SAVE, 'enable_watermark': ENABLE_WATERMARK and not can_edit, } if ONLYOFFICE_JWT_SECRET: import jwt config = { "document": { "fileType": fileext, "key": doc_key, "title": file_name, "url": doc_url, "permissions": { "download": can_download, "edit": can_edit, "print": can_download, "review": True } }, "documentType": document_type, "editorConfig": { "callbackUrl": callback_url, "lang": request.LANGUAGE_CODE, "mode": can_edit, "customization": { "forcesave": ONLYOFFICE_FORCE_SAVE, }, "user": { "name": email2nickname(username) } } } return_dict['onlyoffice_jwt_token'] = jwt.encode( config, ONLYOFFICE_JWT_SECRET) return return_dict
def edit_profile(request): """ Show and edit user profile. """ username = request.user.username form_class = DetailedProfileForm if request.method == 'POST': form = form_class(user=request.user, data=request.POST) if form.is_valid(): form.save() messages.success(request, _('Successfully edited profile.')) return HttpResponseRedirect(reverse('edit_profile')) else: messages.error(request, _('Failed to edit profile')) else: profile = Profile.objects.get_profile_by_user(username) d_profile = DetailedProfile.objects.get_detailed_profile_by_user( username) init_dict = {} if profile: init_dict['nickname'] = profile.nickname init_dict['login_id'] = profile.login_id init_dict['contact_email'] = profile.contact_email init_dict['list_in_address_book'] = profile.list_in_address_book if d_profile: init_dict['department'] = d_profile.department init_dict['telephone'] = d_profile.telephone form = form_class(user=request.user, data=init_dict) # common logic try: server_crypto = UserOptions.objects.is_server_crypto(username) except CryptoOptionNotSetError: # Assume server_crypto is ``False`` if this option is not set. server_crypto = False sub_lib_enabled = UserOptions.objects.is_sub_lib_enabled(username) default_repo_id = UserOptions.objects.get_default_repo(username) if default_repo_id: default_repo = seafile_api.get_repo(default_repo_id) else: default_repo = None owned_repos = get_owned_repo_list(request) owned_repos = [r for r in owned_repos if not r.is_virtual] if settings.ENABLE_WEBDAV_SECRET: decoded = UserOptions.objects.get_webdav_decoded_secret(username) webdav_passwd = decoded if decoded else '' else: webdav_passwd = '' email_inverval = UserOptions.objects.get_file_updates_email_interval(username) email_inverval = email_inverval if email_inverval is not None else 0 if work_weixin_oauth_check(): enable_wechat_work = True from seahub.auth.models import SocialAuthUser from seahub.work_weixin.settings import WORK_WEIXIN_PROVIDER social_connected = SocialAuthUser.objects.filter( username=request.user.username, provider=WORK_WEIXIN_PROVIDER).count() > 0 else: enable_wechat_work = False social_connected = False if ENABLE_DINGTALK: enable_dingtalk = True from seahub.auth.models import SocialAuthUser social_connected_dingtalk = SocialAuthUser.objects.filter( username=request.user.username, provider='dingtalk').count() > 0 else: enable_dingtalk = False social_connected_dingtalk = False resp_dict = { 'form': form, 'server_crypto': server_crypto, "sub_lib_enabled": sub_lib_enabled, 'ENABLE_ADDRESSBOOK_OPT_IN': settings.ENABLE_ADDRESSBOOK_OPT_IN, 'default_repo': default_repo, 'owned_repos': owned_repos, 'is_pro': is_pro_version(), 'is_ldap_user': is_ldap_user(request.user), 'two_factor_auth_enabled': has_two_factor_auth(), 'ENABLE_CHANGE_PASSWORD': settings.ENABLE_CHANGE_PASSWORD, 'ENABLE_WEBDAV_SECRET': settings.ENABLE_WEBDAV_SECRET, 'ENABLE_DELETE_ACCOUNT': ENABLE_DELETE_ACCOUNT, 'ENABLE_UPDATE_USER_INFO': ENABLE_UPDATE_USER_INFO, 'webdav_passwd': webdav_passwd, 'email_notification_interval': email_inverval, 'social_next_page': reverse('edit_profile'), 'enable_wechat_work': enable_wechat_work, 'social_connected': social_connected, 'enable_dingtalk': enable_dingtalk, 'social_connected_dingtalk': social_connected_dingtalk, 'ENABLE_USER_SET_CONTACT_EMAIL': settings.ENABLE_USER_SET_CONTACT_EMAIL, 'user_unusable_password': request.user.enc_password == UNUSABLE_PASSWORD, } if has_two_factor_auth(): from seahub.two_factor.models import StaticDevice, default_device try: backup_tokens = StaticDevice.objects.get( user=request.user.username).token_set.count() except StaticDevice.DoesNotExist: backup_tokens = 0 resp_dict['default_device'] = default_device(request.user) resp_dict['backup_tokens'] = backup_tokens #template = 'profile/set_profile.html' template = 'profile/set_profile_react.html' return render(request, template, resp_dict)
def share_repo(request): """ Handle POST method to share a repo to public/groups/users based on form data. Return to ``myhome`` page and notify user whether success or failure. """ next = request.META.get('HTTP_REFERER', None) if not next: next = SITE_ROOT form = RepoShareForm(request.POST) if not form.is_valid(): # TODO: may display error msg on form raise Http404 email_or_group = form.cleaned_data['email_or_group'] repo_id = form.cleaned_data['repo_id'] permission = form.cleaned_data['permission'] from_email = request.user.username repo = seafile_api.get_repo(repo_id) if not repo: raise Http404 # Test whether user is the repo owner. if not validate_owner(request, repo_id): msg = _(u'Only the owner of the library has permission to share it.') messages.error(request, msg) return HttpResponseRedirect(next) # Parsing input values. share_to_list = string2list(email_or_group) share_to_all, share_to_group_names, share_to_users = False, [], [] for share_to in share_to_list: if share_to == 'all': share_to_all = True elif share_to.find('@') == -1: share_to_group_names.append(share_to) else: share_to = share_to.lower() if is_valid_username(share_to): share_to_users.append(share_to) share_to_groups = [] # get all personal groups for group in request.user.joined_groups: # for every group that user joined, if group name matchs, # then has find the group if group.group_name in share_to_group_names: share_to_groups.append(group) if share_to_all and not CLOUD_MODE: share_to_public(request, repo, permission) if not check_user_share_quota( from_email, repo, users=share_to_users, groups=share_to_groups): messages.error( request, _('Failed to share "%s", no enough quota. <a href="http://seafile.com/">Upgrade account.</a>' ) % repo.name) return HttpResponseRedirect(next) for group in share_to_groups: share_to_group(request, repo, from_email, group, permission) for email in share_to_users: # Add email to contacts. mail_sended.send(sender=None, user=request.user.username, email=email) share_to_user(request, repo, from_email, email, permission) return HttpResponseRedirect(next)
def get(self, request, repo_id, format=None): """ Return history of library 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 if check_folder_permission(request, repo_id, '/') is None: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) username = request.user.username try: server_crypto = UserOptions.objects.is_server_crypto(username) except CryptoOptionNotSetError: # Assume server_crypto is ``False`` if this option is not set. server_crypto = False password_set = False if repo.encrypted and \ (repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)): try: ret = seafile_api.is_password_set(repo_id, username) if ret == 1: password_set = True except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if not password_set: error_msg = 'Library is encrypted, but password is not set in server.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: page = int(request.GET.get('page', '1')) per_page = int(request.GET.get('per_page', '100')) except ValueError: page = 1 per_page = 100 if page <= 0: error_msg = 'page invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if per_page <= 0: error_msg = 'per_page invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) start = (page - 1) * per_page limit = per_page + 1 try: all_commits = seafile_api.get_commit_list(repo_id, start, limit) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) items = [] commits = all_commits[:per_page] for commit in commits: if new_merge_with_no_conflict(commit): continue item_info = self.get_item_info(commit) items.append(item_info) commit_tag_dict = {} if ENABLE_REPO_SNAPSHOT_LABEL: try: revision_tags = RevisionTags.objects.filter(repo_id=repo_id) except Exception as e: logger.error(e) revision_tags = [] for tag in revision_tags: if tag.revision_id in commit_tag_dict: commit_tag_dict[tag.revision_id].append(tag.tag.name) else: commit_tag_dict[tag.revision_id] = [tag.tag.name] for item in items: item['tags'] = [] for commit_id, tags in list(commit_tag_dict.items()): if commit_id == item['commit_id']: item['tags'] = tags result = { 'data': items, 'more': True if len(all_commits) == per_page + 1 else False } return Response(result)
def convert_repo_path_when_can_not_view_folder(request, repo_id, path): content_type = 'application/json; charset=utf-8' path = normalize_dir_path(path) username = request.user.username converted_repo_path = seafile_api.convert_repo_path( repo_id, path, username) if not converted_repo_path: err_msg = _('Permission denied.') return HttpResponse(json.dumps({'error': err_msg}), status=403, content_type=content_type) converted_repo_path = json.loads(converted_repo_path) repo_id = converted_repo_path['repo_id'] repo = seafile_api.get_repo(repo_id) if not repo: err_msg = 'Library not found.' return HttpResponse(json.dumps({'error': err_msg}), status=404, content_type=content_type) path = converted_repo_path['path'] path = normalize_dir_path(path) dir_id = seafile_api.get_dir_id_by_path(repo.id, path) if not dir_id: err_msg = 'Folder not found.' return HttpResponse(json.dumps({'error': err_msg}), status=404, content_type=content_type) group_id = '' if 'group_id' in converted_repo_path: group_id = converted_repo_path['group_id'] if not ccnet_api.get_group(group_id): err_msg = 'Group not found.' return HttpResponse(json.dumps({'error': err_msg}), status=404, content_type=content_type) if not is_group_member(group_id, username): err_msg = _('Permission denied.') return HttpResponse(json.dumps({'error': err_msg}), status=403, content_type=content_type) user_perm = check_folder_permission(request, repo_id, path) if not user_perm: err_msg = _('Permission denied.') return HttpResponse(json.dumps({'error': err_msg}), status=403, content_type=content_type) if not group_id: next_url = '#shared-libs/lib/%s/%s' % (repo_id, path.strip('/')) else: next_url = '#group/%s/lib/%s/%s' % (group_id, repo_id, path.strip('/')) return HttpResponse(json.dumps({'next_url': next_url}), content_type=content_type)
class FileView(APIView): """ Support uniform interface for file related operations, including create/delete/rename/view, etc. """ authentication_classes = (TokenAuthentication, SessionAuthentication) permission_classes = (IsAuthenticated, ) throttle_classes = (UserRateThrottle, ) def get_file_info(self, username, repo_id, file_path): file_obj = seafile_api.get_dirent_by_path(repo_id, file_path) is_locked, locked_by_me = check_file_lock(repo_id, file_path, username) file_info = { 'type': 'file', 'repo_id': repo_id, 'parent_dir': os.path.dirname(file_path), 'obj_name': file_obj.obj_name, 'obj_id': file_obj.obj_id, 'size': file_obj.size, 'mtime': timestamp_to_isoformat_timestr(file_obj.mtime), 'is_locked': is_locked, } return file_info def get(self, request, repo_id, format=None): """ Get file info. Permission checking: 1. user with either 'r' or 'rw' permission. """ # argument check path = request.GET.get('p', None) if not path: error_msg = 'p 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) try: file_id = seafile_api.get_file_id_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 file_id: error_msg = 'File %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check parent_dir = os.path.dirname(path) if check_folder_permission(request, repo_id, parent_dir) is None: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) file_info = self.get_file_info(request.user.username, repo_id, path) return Response(file_info) def post(self, request, repo_id, format=None): """ Create, rename, move, copy file Permission checking: 1. create: user with 'rw' permission for current parent dir; 2. rename: user with 'rw' permission for current file; 3. move : user with 'rw' permission for current file, 'rw' permission for dst parent dir; 4. copy : user with 'r' permission for current file, 'rw' permission for dst parent dir; """ # argument check path = request.GET.get('p', None) if not path or path[0] != '/': error_msg = 'p invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) operation = request.data.get('operation', None) if not operation: error_msg = 'operation invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) operation = operation.lower() if operation not in ('create', 'rename', 'move', 'copy'): error_msg = "operation can only be 'create', 'rename', 'move' or 'copy'." 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) username = request.user.username parent_dir = os.path.dirname(path) if operation == 'create': # resource check try: parent_dir_id = seafile_api.get_dir_id_by_path( repo_id, parent_dir) 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 parent_dir_id: error_msg = 'Folder %s not found.' % parent_dir return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check if check_folder_permission(request, repo_id, parent_dir) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # create file new_file_name = os.path.basename(path) new_file_name = check_filename_with_rename(repo_id, parent_dir, new_file_name) try: seafile_api.post_empty_file(repo_id, parent_dir, new_file_name, username) except SearpcError, e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) new_file_path = posixpath.join(parent_dir, new_file_name) file_info = self.get_file_info(username, repo_id, new_file_path) return Response(file_info) if operation == 'rename': # argument check new_file_name = request.data.get('newname', None) if not new_file_name: error_msg = 'newname invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if len(new_file_name) > MAX_UPLOAD_FILE_NAME_LEN: error_msg = 'newname is too long.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) oldname = os.path.basename(path) if oldname == new_file_name: error_msg = 'The new name is the same to the old' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # resource check try: file_id = seafile_api.get_file_id_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 file_id: error_msg = 'File %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check if check_folder_permission(request, repo_id, parent_dir) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # rename file new_file_name = check_filename_with_rename(repo_id, parent_dir, new_file_name) try: seafile_api.rename_file(repo_id, parent_dir, oldname, new_file_name, username) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) new_file_path = posixpath.join(parent_dir, new_file_name) file_info = self.get_file_info(username, repo_id, new_file_path) return Response(file_info) if operation == 'move': # argument check dst_repo_id = request.data.get('dst_repo', None) dst_dir = request.data.get('dst_dir', None) if not dst_repo_id: error_msg = 'dst_repo invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if not dst_dir: error_msg = 'dst_dir invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # resource check for source file try: file_id = seafile_api.get_file_id_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 file_id: error_msg = 'File %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) # resource check for dst repo and dir dst_repo = seafile_api.get_repo(dst_repo_id) if not dst_repo: error_msg = 'Library %s not found.' % dst_repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) dst_dir_id = seafile_api.get_dir_id_by_path(dst_repo_id, dst_dir) if not dst_dir_id: error_msg = 'Folder %s not found.' % dst_dir return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check for source file src_repo_id = repo_id src_dir = os.path.dirname(path) if check_folder_permission(request, src_repo_id, src_dir) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # permission check for dst dir if check_folder_permission(request, dst_repo_id, dst_dir) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # move file if dst_dir[ -1] != '/': # Append '/' to the end of directory if necessary dst_dir += '/' if src_repo_id == dst_repo_id and src_dir == dst_dir: file_info = self.get_file_info(username, repo_id, path) return Response(file_info) filename = os.path.basename(path) new_file_name = check_filename_with_rename(dst_repo_id, dst_dir, filename) try: seafile_api.move_file(src_repo_id, src_dir, filename, dst_repo_id, dst_dir, new_file_name, replace=False, username=username, need_progress=0, synchronous=1) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) dst_file_path = posixpath.join(dst_dir, new_file_name) dst_file_info = self.get_file_info(username, dst_repo_id, dst_file_path) return Response(dst_file_info) if operation == 'copy': # argument check dst_repo_id = request.data.get('dst_repo', None) dst_dir = request.data.get('dst_dir', None) if not dst_repo_id: error_msg = 'dst_repo_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if not dst_dir: error_msg = 'dst_dir invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # resource check for source file try: file_id = seafile_api.get_file_id_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 file_id: error_msg = 'File %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) # resource check for dst repo and dir dst_repo = seafile_api.get_repo(dst_repo_id) if not dst_repo: error_msg = 'Library %s not found.' % dst_repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) dst_dir_id = seafile_api.get_dir_id_by_path(dst_repo_id, dst_dir) if not dst_dir_id: error_msg = 'Folder %s not found.' % dst_dir return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check for source file src_repo_id = repo_id src_dir = os.path.dirname(path) if not check_folder_permission(request, src_repo_id, src_dir): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # permission check for dst dir if check_folder_permission(request, dst_repo_id, dst_dir) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # copy file if dst_dir[ -1] != '/': # Append '/' to the end of directory if necessary dst_dir += '/' if src_repo_id == dst_repo_id and src_dir == dst_dir: file_info = self.get_file_info(username, repo_id, path) return Response(file_info) filename = os.path.basename(path) new_file_name = check_filename_with_rename(dst_repo_id, dst_dir, filename) try: seafile_api.copy_file(src_repo_id, src_dir, filename, dst_repo_id, dst_dir, new_file_name, username, 0, synchronous=1) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) dst_file_path = posixpath.join(dst_dir, new_file_name) dst_file_info = self.get_file_info(username, dst_repo_id, dst_file_path) return Response(dst_file_info)
def get(self, request, token): """ Only used for get dirents in a folder share link. Permission checking: 1, If enable SHARE_LINK_LOGIN_REQUIRED, user must have been authenticated. 2, If enable ENABLE_SHARE_LINK_AUDIT, user must have been authenticated, or have been audited. 3, If share link is encrypted, share link password must have been checked. """ # argument check thumbnail_size = request.GET.get('thumbnail_size', 48) try: thumbnail_size = int(thumbnail_size) except ValueError: error_msg = 'thumbnail_size invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # permission check # check if login required if SHARE_LINK_LOGIN_REQUIRED and \ not request.user.is_authenticated(): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # check share link audit if is_pro_version() and ENABLE_SHARE_LINK_AUDIT and \ not request.user.is_authenticated() and \ not request.session.get('anonymous_email'): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # resource check try: share_link = FileShare.objects.get(token=token) except FileShare.DoesNotExist: error_msg = 'Share link %s not found.' % token return api_error(status.HTTP_404_NOT_FOUND, error_msg) # check share link password if share_link.is_encrypted() and not check_share_link_access( request, token): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if share_link.s_type != 'd': error_msg = 'Share link %s is not a folder share link.' % token return api_error(status.HTTP_400_BAD_REQUEST, error_msg) repo_id = share_link.repo_id 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) share_link_path = share_link.path request_path = request.GET.get('path', '/') if request_path == '/': path = share_link_path else: path = posixpath.join(share_link_path, request_path.strip('/')) path = normalize_dir_path(path) dir_id = seafile_api.get_dir_id_by_path(repo_id, path) if not dir_id: error_msg = 'Folder %s not found.' % request_path return api_error(status.HTTP_404_NOT_FOUND, error_msg) try: current_commit = seafile_api.get_commit_list(repo_id, 0, 1)[0] dirent_list = seafile_api.list_dir_by_commit_and_path( repo_id, current_commit.id, path, -1, -1) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) result = [] for dirent in dirent_list: # don't return parent folder(share link path) info to user # so use request_path here dirent_path = posixpath.join(request_path, dirent.obj_name) dirent_info = {} dirent_info['size'] = dirent.size dirent_info['last_modified'] = timestamp_to_isoformat_timestr( dirent.mtime) if stat.S_ISDIR(dirent.mode): dirent_info['is_dir'] = True dirent_info['folder_path'] = normalize_dir_path(dirent_path) dirent_info['folder_name'] = dirent.obj_name else: dirent_info['is_dir'] = False dirent_info['file_path'] = normalize_file_path(dirent_path) dirent_info['file_name'] = dirent.obj_name file_type, file_ext = get_file_type_and_ext(dirent.obj_name) if file_type in (IMAGE, XMIND) or \ file_type == VIDEO and ENABLE_VIDEO_THUMBNAIL: if os.path.exists( os.path.join(THUMBNAIL_ROOT, str(thumbnail_size), dirent.obj_id)): req_image_path = posixpath.join( request_path, dirent.obj_name) src = get_share_link_thumbnail_src( token, thumbnail_size, req_image_path) dirent_info['encoded_thumbnail_src'] = urlquote(src) result.append(dirent_info) return Response({'dirent_list': result})
def get_repo(repo_id): return seafile_api.get_repo(repo_id)
def get(self, request): """get all workspaces """ username = request.user.username org_id = -1 if is_org_context(request): org_id = request.user.org.org_id if org_id > 0: groups = ccnet_api.get_org_groups_by_user(org_id, username) else: groups = ccnet_api.get_groups(username, return_ancestors=True) owner_list = list() owner_list.append(username) for group in groups: group_user = '******' % group.id owner_list.append(group_user) workspace_list = list() for owner in owner_list: try: workspace = Workspaces.objects.get_workspace_by_owner(owner) except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if not workspace: if '@seafile_group' in owner: continue # permission check if not request.user.permissions.can_add_repo(): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) try: if org_id > 0: repo_id = seafile_api.create_org_repo( _("My Workspace"), _("My Workspace"), "dtable@seafile", org_id) else: repo_id = seafile_api.create_repo( _("My Workspace"), _("My Workspace"), "dtable@seafile") except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) workspace = Workspaces.objects.create_workspace(owner, repo_id) # resource check repo_id = workspace.repo_id repo = seafile_api.get_repo(repo_id) if not repo: logger.warning('Library %s not found.' % repo_id) continue if '@seafile_group' in owner: group_id = int(owner.split('@')[0]) owner_name = group_id_to_name(group_id) owner_type = "Group" else: owner_name = email2nickname(owner) owner_type = "Personal" table_list = DTables.objects.get_dtable_by_workspace(workspace) res = workspace.to_dict() res["owner_name"] = owner_name res["owner_type"] = owner_type res["table_list"] = table_list workspace_list.append(res) return Response({"workspace_list": workspace_list}, status=status.HTTP_200_OK)
def put(self, request, token): """ Update share link, currently only available for permission. Permission checking: 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: fs = FileShare.objects.get(token=token) except FileShare.DoesNotExist: error_msg = 'token %s not found.' % token 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 if not fs.is_owner(username): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # get permission of origin repo/folder if fs.s_type == 'd': folder_path = normalize_dir_path(fs.path) else: 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, error_msg = 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) return Response(link_info)
def post(self, request): """ Create upload link. Permission checking: 1. default(NOT guest) user; 2. user with 'rw' permission; """ # argument check repo_id = request.data.get('repo_id', None) if not repo_id: error_msg = 'repo_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) path = request.data.get('path', None) if not path: error_msg = 'path invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) password = request.data.get('password', None) if password and len(password) < config.SHARE_LINK_PASSWORD_MIN_LENGTH: error_msg = _('Password is too short') return api_error(status.HTTP_400_BAD_REQUEST, error_msg) expire_days = request.data.get('expire_days', '') expiration_time = request.data.get('expiration_time', '') if expire_days and expiration_time: error_msg = 'Can not pass expire_days and expiration_time at the same time.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) expire_date = None if expire_days: try: expire_days = int(expire_days) except ValueError: error_msg = 'expire_days invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if expire_days <= 0: error_msg = 'expire_days invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if UPLOAD_LINK_EXPIRE_DAYS_MIN > 0: if expire_days < UPLOAD_LINK_EXPIRE_DAYS_MIN: error_msg = _('Expire days should be greater or equal to %s') % \ UPLOAD_LINK_EXPIRE_DAYS_MIN return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if UPLOAD_LINK_EXPIRE_DAYS_MAX > 0: if expire_days > UPLOAD_LINK_EXPIRE_DAYS_MAX: error_msg = _('Expire days should be less than or equal to %s') % \ UPLOAD_LINK_EXPIRE_DAYS_MAX return api_error(status.HTTP_400_BAD_REQUEST, error_msg) expire_date = timezone.now() + relativedelta(days=expire_days) elif expiration_time: try: expire_date = dateutil.parser.isoparse(expiration_time) except Exception as e: logger.error(e) error_msg = 'expiration_time invalid, should be iso format, for example: 2020-05-17T10:26:22+08:00' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) expire_date = expire_date.astimezone( get_current_timezone()).replace(tzinfo=None) if UPLOAD_LINK_EXPIRE_DAYS_MIN > 0: expire_date_min_limit = timezone.now() + relativedelta( days=UPLOAD_LINK_EXPIRE_DAYS_MIN) expire_date_min_limit = expire_date_min_limit.replace( hour=0).replace(minute=0).replace(second=0) if expire_date < expire_date_min_limit: error_msg = _('Expiration time should be later than %s.') % \ expire_date_min_limit.strftime("%Y-%m-%d %H:%M:%S") return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if UPLOAD_LINK_EXPIRE_DAYS_MAX > 0: expire_date_max_limit = timezone.now() + relativedelta( days=UPLOAD_LINK_EXPIRE_DAYS_MAX) expire_date_max_limit = expire_date_max_limit.replace( hour=23).replace(minute=59).replace(second=59) if expire_date > expire_date_max_limit: error_msg = _('Expiration time should be earlier than %s.') % \ expire_date_max_limit.strftime("%Y-%m-%d %H:%M:%S") return api_error(status.HTTP_400_BAD_REQUEST, error_msg) else: if UPLOAD_LINK_EXPIRE_DAYS_DEFAULT > 0: expire_date = timezone.now() + relativedelta( days=UPLOAD_LINK_EXPIRE_DAYS_DEFAULT) # 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) try: dir_id = seafile_api.get_dir_id_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 dir_id: error_msg = 'folder %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) if check_folder_permission(request, repo_id, path) != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) username = request.user.username uls = UploadLinkShare.objects.get_upload_link_by_path( username, repo_id, path) if not uls: uls = UploadLinkShare.objects.create_upload_link_share( username, repo_id, path, password, expire_date) link_info = get_upload_link_info(uls) return Response(link_info)
def delete(self, request, repo_id, format=None): """ Delete repo group folder perm. Permission checking: 1. is group admin """ # arguments check group_id = request.data.get('group_id', None) path = request.data.get('folder_path', None) if not group_id: error_msg = 'group_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if not path: error_msg = 'folder_path invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: group_id = int(group_id) except ValueError: error_msg = 'group_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # resource check if not ccnet_api.get_group(group_id): error_msg = 'Group %s not found.' % group_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) 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) repo_owner = get_repo_owner(request, repo_id) library_group_id = get_group_id_by_repo_owner(repo_owner) if not ccnet_api.get_group(library_group_id): error_msg = 'Group %s not found.' % group_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check username = request.user.username if not is_group_admin(library_group_id, username): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # delete permission path = path.rstrip('/') if path != '/' else path permission = seafile_api.get_folder_group_perm(repo_id, path, group_id) if not permission: return Response({'success': True}) try: seafile_api.rm_folder_group_perm(repo_id, path, group_id) send_perm_audit_msg('delete-repo-perm', username, group_id, repo_id, path, permission) return Response({'success': True}) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
def post(self, request, group_id): """ Add a group owned library. Permission checking: 1. role permission, can_add_repo; 1. is group admin; """ # argument check repo_name = request.data.get("name", None) if not repo_name or \ not is_valid_dirent_name(repo_name): error_msg = "name invalid." return api_error(status.HTTP_400_BAD_REQUEST, error_msg) password = request.data.get("passwd", None) if password and not config.ENABLE_ENCRYPTED_LIBRARY: error_msg = 'NOT allow to create encrypted library.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) permission = request.data.get('permission', PERMISSION_READ_WRITE) if permission not in [PERMISSION_READ, PERMISSION_READ_WRITE]: error_msg = 'permission invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # permission check if not request.user.permissions.can_add_repo(): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if not is_group_admin(group_id, request.user.username): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) group_quota = seafile_api.get_group_quota(group_id) group_quota = int(group_quota) if group_quota <= 0 and group_quota != -2: error_msg = 'No group quota.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # create group owned repo group_id = int(group_id) if is_pro_version() and ENABLE_STORAGE_CLASSES: if STORAGE_CLASS_MAPPING_POLICY in ('USER_SELECT', 'ROLE_BASED'): storages = get_library_storages(request) storage_id = request.data.get("storage_id", None) if storage_id and storage_id not in [ s['storage_id'] for s in storages ]: error_msg = 'storage_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) repo_id = seafile_api.add_group_owned_repo( group_id, repo_name, password, permission, storage_id) else: # STORAGE_CLASS_MAPPING_POLICY == 'REPO_ID_MAPPING' repo_id = seafile_api.add_group_owned_repo( group_id, repo_name, password, permission) else: repo_id = seafile_api.add_group_owned_repo(group_id, repo_name, password, permission) # for activities org_id = -1 username = request.user.username library_template = request.data.get("library_template", '') repo_created.send(sender=None, org_id=org_id, creator=username, repo_id=repo_id, repo_name=repo_name, library_template=library_template) # for notification repo = seafile_api.get_repo(repo_id) share_repo_to_group_successful.send(sender=None, from_user=username, group_id=group_id, repo=repo, path='/', org_id=org_id) info = get_group_owned_repo_info(request, repo_id) # TODO info['permission'] = permission return Response(info)
def get(self, request): """ Get all share links of a user. Permission checking: 1. default(NOT guest) user; """ username = request.user.username repo_id = request.GET.get('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) if not repo: error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) fileshares = FileShare.objects.filter(username=username) \ .filter(repo_id=repo_id) # share links by repo and path if repo_id and path: 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 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) if stat.S_ISDIR(dirent.mode): path = normalize_dir_path(path) else: path = normalize_file_path(path) 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 = [] for fs in fileshares: 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) if len(links_info) == 1: result = links_info else: dir_list = [x for x in links_info if x['is_dir']] file_list = [x for x in links_info if not x['is_dir']] dir_list.sort(key=lambda x: x['obj_name']) file_list.sort(key=lambda x: x['obj_name']) result = dir_list + file_list return Response(result)
def get_wopi_dict(request_user, repo_id, file_path, action_name='view'): """ Prepare dict data for WOPI host page """ if action_name not in ('view', 'edit'): return None file_name = os.path.basename(file_path) file_ext = os.path.splitext(file_name)[1][1:].lower() if OFFICE_SERVER_TYPE.lower() == 'collaboraoffice': if file_ext == 'doc': file_ext = 'docx' if file_ext == 'ppt': file_ext = 'pptx' if file_ext == 'xls': file_ext = 'xlsx' wopi_key = generate_discovery_cache_key(action_name, file_ext) action_url = cache.get(wopi_key) if not action_url: # can not get action_url from cache try: if OFFICE_WEB_APP_CLIENT_CERT and OFFICE_WEB_APP_CLIENT_KEY: xml = requests.get(OFFICE_WEB_APP_BASE_URL, cert=(OFFICE_WEB_APP_CLIENT_CERT, OFFICE_WEB_APP_CLIENT_KEY), verify=OFFICE_WEB_APP_SERVER_CA) elif OFFICE_WEB_APP_CLIENT_PEM: xml = requests.get(OFFICE_WEB_APP_BASE_URL, cert=OFFICE_WEB_APP_CLIENT_PEM, verify=OFFICE_WEB_APP_SERVER_CA) else: xml = requests.get(OFFICE_WEB_APP_BASE_URL, verify=OFFICE_WEB_APP_SERVER_CA) except Exception as e: logger.error(e) return None try: root = ET.fromstring(xml.content) except Exception as e: logger.error(e) return None for action in root.getiterator('action'): attr = action.attrib ext = attr.get('ext') name = attr.get('name') urlsrc = attr.get('urlsrc') if ext and name and urlsrc: tmp_action_url = re.sub(r'<.*>', '', urlsrc) tmp_wopi_key = generate_discovery_cache_key(name, ext) cache.set(tmp_wopi_key, tmp_action_url, OFFICE_WEB_APP_DISCOVERY_EXPIRATION) if wopi_key == tmp_wopi_key: action_url = tmp_action_url else: continue if not action_url: # can not get action_url from hosting discovery page return None # generate full action url repo = seafile_api.get_repo(repo_id) if repo.is_virtual: origin_repo_id = repo.origin_repo_id origin_file_path = posixpath.join(repo.origin_path, file_path.strip('/')) repo_path_info = '_'.join([origin_repo_id, origin_file_path]) else: repo_path_info = '_'.join([repo_id, file_path]) fake_file_id = hashlib.sha1(repo_path_info.encode('utf8')).hexdigest() base_url = get_site_scheme_and_netloc() check_file_info_endpoint = reverse('WOPIFilesView', args=[fake_file_id]) WOPISrc = urlparse.urljoin(base_url, check_file_info_endpoint) query_dict = {'WOPISrc': WOPISrc} if action_url[-1] in ('?', '&'): full_action_url = action_url + urllib.urlencode(query_dict) elif '?' in action_url: full_action_url = action_url + '&' + urllib.urlencode(query_dict) else: full_action_url = action_url + '?' + urllib.urlencode(query_dict) lang_code = Profile.objects.get_user_language(request_user) if lang_code.lower() == 'zh-cn': full_action_url += '&ui=zh-CN&rs=zh-CN' # generate access token user_repo_path_info = (request_user, repo_id, file_path) # collobora office only allowed alphanumeric and _ uid = uuid.uuid4() access_token = uid.hex key = generate_access_token_cache_key(access_token) cache.set(key, user_repo_path_info, WOPI_ACCESS_TOKEN_EXPIRATION) # access_token_ttl property tells office web app # when access token expires expire_sec = WOPI_ACCESS_TOKEN_EXPIRATION expiration = timezone.now() + relativedelta(seconds=expire_sec) milliseconds_ttl = time.mktime(expiration.timetuple()) * 1000 access_token_ttl = int(milliseconds_ttl) wopi_dict = {} wopi_dict['action_url'] = full_action_url wopi_dict['access_token'] = access_token wopi_dict['access_token_ttl'] = access_token_ttl return wopi_dict
def put(self, request, repo_id, format=None): """ Modify repo group folder perm. Permission checking: 1. is group admin """ # argument check path = request.data.get('folder_path', None) if not path: error_msg = 'folder_path invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) perm = request.data.get('permission', None) if not perm or perm not in [PERMISSION_READ, PERMISSION_READ_WRITE]: error_msg = 'permission invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) group_id = request.data.get('group_id') 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 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) path = normalize_dir_path(path) if not seafile_api.get_dir_id_by_path(repo_id, path): error_msg = 'Folder %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) if not ccnet_api.get_group(group_id): error_msg = 'Group %s not found.' % group_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) repo_owner = get_repo_owner(request, repo_id) library_group_id = get_group_id_by_repo_owner(repo_owner) if not ccnet_api.get_group(library_group_id): error_msg = 'Group %s not found.' % group_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) permission = seafile_api.get_folder_group_perm(repo_id, path, group_id) if not permission: error_msg = 'Folder permission not found.' return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check username = request.user.username if not is_group_admin(library_group_id, username): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # modify permission try: seafile_api.set_folder_group_perm(repo_id, path, perm, group_id) send_perm_audit_msg('modify-repo-perm', username, group_id, repo_id, path, perm) new_perm = seafile_api.get_folder_group_perm( repo_id, path, group_id) result = self._get_group_folder_perm_info(group_id, repo_id, path, new_perm) return Response(result) except Exception as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
def post(self, request): # argument check operation = request.data.get('operation') # operation could be `share`, `delete`, `transfer` # we now only use `share` if not operation or operation not in ('share'): error_msg = 'operation invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) result = {} result['failed'] = [] result['success'] = [] username = request.user.username repo_id_list = request.data.getlist('repo_id') valid_repo_id_list = [] # filter out invalid repo id for repo_id in repo_id_list: if not seafile_api.get_repo(repo_id): result['failed'].append({ 'repo_id': repo_id, 'error_msg': 'Library %s not found.' % repo_id }) continue if is_org_context(request): org_id = request.user.org.org_id org_repo_owner = seafile_api.get_org_repo_owner(repo_id) if not username == org_repo_owner: result['failed'].append({ 'repo_id': repo_id, 'error_msg': 'Permission denied.' }) continue else: if not seafile_api.is_repo_owner(username, repo_id): result['failed'].append({ 'repo_id': repo_id, 'error_msg': 'Permission denied.' }) continue valid_repo_id_list.append(repo_id) # share repo if operation == 'share': share_type = request.data.get('share_type') if share_type != 'user' and share_type != 'group': error_msg = 'share_type invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) permission = request.data.get('permission', 'rw') if permission not in ('r', 'rw'): error_msg = 'permission invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # share repo to user if share_type == 'user': to_username = request.data.get('username', None) if not to_username: error_msg = 'username invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: User.objects.get(email=to_username) except User.DoesNotExist: error_msg = 'User %s not found.' % to_username return api_error(status.HTTP_404_NOT_FOUND, error_msg) # check if to_user is an org user try: org_of_to_user = ccnet_api.get_orgs_by_user(to_username) except Exception as e: logger.debug(e) org_of_to_user = [] if is_org_context(request): org_id = request.user.org.org_id org_name = request.user.org.org_name if len(org_of_to_user ) == 0 or org_id != org_of_to_user[0].org_id: error_msg = 'User %s is not member of organization %s.' \ % (to_username, org_name) return api_error(status.HTTP_403_FORBIDDEN, error_msg) else: if len(org_of_to_user) >= 1: error_msg = 'User %s is member of organization %s.' \ % (to_username, org_of_to_user[0].org_name) return api_error(status.HTTP_403_FORBIDDEN, error_msg) for repo_id in valid_repo_id_list: if self.has_shared_to_user(request, repo_id, to_username): result['failed'].append({ 'repo_id': repo_id, 'error_msg': 'This item has been shared to %s.' % to_username }) continue try: if is_org_context(request): org_id = request.user.org.org_id seaserv.seafserv_threaded_rpc.org_add_share( org_id, repo_id, username, to_username, permission) else: seafile_api.share_repo(repo_id, username, to_username, permission) # send a signal when sharing repo successful repo = seafile_api.get_repo(repo_id) share_repo_to_user_successful.send(sender=None, from_user=username, to_user=to_username, repo=repo) result['success'].append({ "repo_id": repo_id, "username": to_username, "permission": permission }) send_perm_audit_msg('add-repo-perm', username, to_username, repo_id, '/', permission) except Exception as e: logger.error(e) result['failed'].append({ 'repo_id': repo_id, 'error_msg': 'Internal Server Error' }) # share repo to group if share_type == 'group': to_group_id = request.data.get('group_id', None) if not to_group_id: error_msg = 'group_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: to_group_id = int(to_group_id) except ValueError: error_msg = 'group_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) group = ccnet_api.get_group(to_group_id) if not group: error_msg = 'Group %s not found.' % to_group_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) group_name = group.group_name if not ccnet_api.is_group_user(to_group_id, username): error_msg = 'User %s is not member of group %s.' % ( username, group_name) return api_error(status.HTTP_403_FORBIDDEN, error_msg) for repo_id in valid_repo_id_list: if self.has_shared_to_group(request, repo_id, to_group_id): result['failed'].append({ 'repo_id': repo_id, 'error_msg': 'This item has been shared to %s.' % group_name }) continue try: if is_org_context(request): org_id = request.user.org.org_id seafile_api.add_org_group_repo( repo_id, org_id, to_group_id, username, permission) else: seafile_api.set_group_repo(repo_id, to_group_id, username, permission) # send a signal when sharing repo successful repo = seafile_api.get_repo(repo_id) share_repo_to_group_successful.send( sender=None, from_user=username, group_id=to_group_id, repo=repo) result['success'].append({ "repo_id": repo_id, "group_id": to_group_id, "group_name": group_name, "permission": permission }) send_perm_audit_msg('add-repo-perm', username, to_group_id, repo_id, '/', permission) except SearpcError as e: logger.error(e) result['failed'].append({ 'repo_id': repo_id, 'error_msg': 'Internal Server Error' }) return Response(result)
def post(self, request, repo_id, format=None): """ Add repo group folder perm. Permission checking: 1. is group admin """ # argument check path = request.data.get('folder_path', None) if not path: error_msg = 'folder_path invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) perm = request.data.get('permission', None) if not perm or perm not in [PERMISSION_READ, PERMISSION_READ_WRITE]: error_msg = 'permission 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) path = normalize_dir_path(path) if not seafile_api.get_dir_id_by_path(repo_id, path): error_msg = 'Folder %s not found.' % path return api_error(status.HTTP_404_NOT_FOUND, error_msg) repo_owner = get_repo_owner(request, repo_id) group_id = get_group_id_by_repo_owner(repo_owner) if not ccnet_api.get_group(group_id): error_msg = 'Group %s not found.' % group_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check username = request.user.username if not is_group_admin(group_id, username): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) result = {} result['failed'] = [] result['success'] = [] group_ids = request.data.getlist('group_id') for group_id in group_ids: try: group_id = int(group_id) except ValueError: result['failed'].append({ 'group_id': group_id, 'error_msg': 'group_id invalid.' }) continue if not ccnet_api.get_group(group_id): result['failed'].append({ 'group_id': group_id, 'error_msg': 'Group %s not found.' % group_id }) continue permission = seafile_api.get_folder_group_perm( repo_id, path, group_id) if permission: result['failed'].append({ 'group_id': group_id, 'error_msg': _(u'Permission already exists.') }) continue try: seafile_api.add_folder_group_perm(repo_id, path, perm, group_id) send_perm_audit_msg('add-repo-perm', username, group_id, repo_id, path, perm) except Exception as e: logger.error(e) result['failed'].append({ 'group_id': group_id, 'error_msg': 'Internal Server Error' }) new_perm = seafile_api.get_folder_group_perm( repo_id, path, group_id) new_perm_info = self._get_group_folder_perm_info( group_id, repo_id, path, new_perm) result['success'].append(new_perm_info) return Response(result)
def post(self, request): """ Multi copy folders. Permission checking: 1. User must has `r/rw` permission for src folder. 2. User must has `rw` permission for dst folder. Parameter: { "src_repo_id":"7460f7ac-a0ff-4585-8906-bb5a57d2e118", "dst_repo_id":"a3fa768d-0f00-4343-8b8d-07b4077881db", "paths":[ {"src_path":"/1/2/3/","dst_path":"/4/5/6/"}, {"src_path":"/a/b/c/","dst_path":"/d/e/f/"}, ] } """ # argument check path_list = request.data.get('paths', None) if not path_list: error_msg = 'paths invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) src_repo_id = request.data.get('src_repo_id', None) if not src_repo_id: error_msg = 'src_repo_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) dst_repo_id = request.data.get('dst_repo_id', None) if not dst_repo_id: error_msg = 'dst_repo_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # permission check, user must has `r/rw` permission for src repo. if check_folder_permission(request, src_repo_id, '/') is None: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # permission check, user must has `rw` permission for dst repo. if check_folder_permission(request, dst_repo_id, '/') != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # resource check src_repo = seafile_api.get_repo(src_repo_id) if not src_repo: error_msg = 'Library %s not found.' % src_repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) dst_repo = seafile_api.get_repo(dst_repo_id) if not dst_repo: error_msg = 'Library %s not found.' % dst_repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) result = {} result['failed'] = [] result['success'] = [] username = request.user.username for path_item in path_list: src_path = path_item['src_path'] src_path = normalize_dir_path(src_path) src_parent_dir = os.path.dirname(src_path.rstrip('/')) src_parent_dir = normalize_dir_path(src_parent_dir) src_obj_name = os.path.basename(src_path.rstrip('/')) dst_path = path_item['dst_path'] dst_path = normalize_dir_path(dst_path) dst_parent_dir = dst_path dst_obj_name = src_obj_name common_dict = { 'src_repo_id': src_repo_id, 'src_path': src_path, 'dst_repo_id': dst_repo_id, 'dst_path': dst_path, } # src/dst parameter check if src_repo_id == dst_repo_id and \ dst_path.startswith(src_path): error_dict = { 'error_msg': "The destination directory is the same as the source, or is it's subfolder." } common_dict.update(error_dict) result['failed'].append(common_dict) continue if src_path == '/': error_dict = {'error_msg': "The source path can not be '/'."} common_dict.update(error_dict) result['failed'].append(common_dict) continue if len(dst_parent_dir + dst_obj_name) > MAX_PATH: error_dict = {'error_msg': "'Destination path is too long."} common_dict.update(error_dict) result['failed'].append(common_dict) continue # src resource check if not seafile_api.get_dir_id_by_path(src_repo_id, src_path): error_dict = {'error_msg': 'Folder %s not found.' % src_path} common_dict.update(error_dict) result['failed'].append(common_dict) continue # dst resource check if not seafile_api.get_dir_id_by_path(dst_repo_id, dst_path): error_dict = {'error_msg': 'Folder %s not found.' % dst_path} common_dict.update(error_dict) result['failed'].append(common_dict) continue # src path permission check, user must has `r/rw` permission for src folder. if check_folder_permission(request, src_repo_id, src_parent_dir) is None: error_dict = {'error_msg': 'Permission denied.'} common_dict.update(error_dict) result['failed'].append(common_dict) continue # dst path permission check, user must has `rw` permission for dst folder. if check_folder_permission(request, dst_repo_id, dst_path) != 'rw': error_dict = {'error_msg': 'Permission denied.'} common_dict.update(error_dict) result['failed'].append(common_dict) continue try: # need_progress=0, synchronous=1 seafile_api.copy_file(src_repo_id, src_parent_dir, src_obj_name, dst_repo_id, dst_parent_dir, dst_obj_name, username, 0, 1) except Exception as e: logger.error(e) error_dict = {'error_msg': 'Internal Server Error'} common_dict.update(error_dict) result['failed'].append(common_dict) continue result['success'].append(common_dict) return Response(result)
def post(self, request): """ Multi create folders. Permission checking: 1. user with `rw` permission for every layer of subdirectories. Parameter: { "repo_id": "4dfdf5b6-806f-4a35-b2b7-604051d2114e", "paths": ["/1/2/", "/3/4/", "/5/6"] } """ # argument check path_list = request.data.get('paths', None) if not path_list: error_msg = 'paths invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) repo_id = request.data.get('repo_id', None) if not repo_id: error_msg = 'repo_id 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) # permission check if check_folder_permission(request, repo_id, '/') != 'rw': error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) result = {} result['failed'] = [] result['success'] = [] username = request.user.username for path in path_list: common_dict = { 'repo_id': repo_id, 'path': path, } path = normalize_dir_path(path) obj_name_list = path.strip('/').split('/') for obj_name in obj_name_list: try: # check if path is valid is_valid_name = seafile_api.is_valid_filename( 'fake_repo_id', obj_name) except Exception as e: logger.error(e) error_dict = {'error_msg': 'Internal Server Error'} common_dict.update(error_dict) result['failed'].append(common_dict) continue if not is_valid_name: error_dict = {'error_msg': 'path invalid.'} common_dict.update(error_dict) result['failed'].append(common_dict) continue if seafile_api.get_dir_id_by_path(repo_id, path): error_dict = {'error_msg': 'Folder already exists.'} common_dict.update(error_dict) result['failed'].append(common_dict) continue # check parent directory's permission parent_dir = os.path.dirname(path.rstrip('/')) try: permission = get_folder_permission_recursively( username, repo_id, parent_dir) except Exception as e: logger.error(e) error_dict = {'error_msg': 'Internal Server Error'} common_dict.update(error_dict) result['failed'].append(common_dict) continue if permission != 'rw': error_dict = {'error_msg': 'Permission denied.'} common_dict.update(error_dict) result['failed'].append(common_dict) continue try: # TODO # move seafile_api.mkdir_with_parents() to CE version # rename obj name if name is existed seafile_api.mkdir_with_parents(repo_id, '/', path.strip('/'), username) except Exception as e: logger.error(e) error_dict = {'error_msg': 'Internal Server Error'} common_dict.update(error_dict) result['failed'].append(common_dict) continue result['success'].append(common_dict) return Response(result)
def post(self, request): """ Create share link. Permission checking: 1. default(NOT guest) user; """ # argument check repo_id = request.data.get('repo_id', None) if not repo_id: error_msg = 'repo_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) path = request.data.get('path', None) if not path: error_msg = 'path invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) password = request.data.get('password', None) if password and len(password) < config.SHARE_LINK_PASSWORD_MIN_LENGTH: error_msg = _('Password is too short.') return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: expire_days = int(request.data.get('expire_days', 0)) except ValueError: expire_days = 0 if SHARE_LINK_EXPIRE_DAYS_MIN > 0: if expire_days < SHARE_LINK_EXPIRE_DAYS_MIN: error_msg = _('Expire days should be greater or equal to %s' % SHARE_LINK_EXPIRE_DAYS_MIN) return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if SHARE_LINK_EXPIRE_DAYS_MAX > 0: if expire_days > SHARE_LINK_EXPIRE_DAYS_MAX: error_msg = _('Expire days should be less than or equal to %s' % SHARE_LINK_EXPIRE_DAYS_MAX) return api_error(status.HTTP_400_BAD_REQUEST, error_msg) if expire_days <= 0: expire_date = None else: expire_date = timezone.now() + relativedelta(days=expire_days) perm = self._check_permissions_arg(request) # 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 repo.encrypted: error_msg = 'Permission denied.' 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) # permission check if not check_folder_permission(request, repo_id, path): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) username = request.user.username if s_type == 'f': fs = FileShare.objects.get_file_link_by_path(username, repo_id, path) if not fs: fs = FileShare.objects.create_file_link(username, repo_id, path, password, expire_date, permission=perm) elif s_type == 'd': fs = FileShare.objects.get_dir_link_by_path(username, repo_id, path) if not fs: fs = FileShare.objects.create_dir_link(username, repo_id, path, password, expire_date, permission=perm) if is_org_context(request): org_id = request.user.org.org_id OrgFileShare.objects.set_org_file_share(org_id, fs) link_info = get_share_link_info(fs) return Response(link_info)
def post(self, request, group_id): """ Add a group owned library by system admin. """ if not request.user.admin_permissions.can_manage_group(): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied.') # argument check repo_name = request.data.get("repo_name", None) if not repo_name or \ not is_valid_dirent_name(repo_name): error_msg = "repo_name invalid." return api_error(status.HTTP_400_BAD_REQUEST, error_msg) password = request.data.get("password", None) permission = request.data.get('permission', PERMISSION_READ_WRITE) if permission not in get_available_repo_perms(): permission = normalize_custom_permission_name(permission) if not permission: error_msg = 'permission invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) # permission check group_quota = seafile_api.get_group_quota(group_id) group_quota = int(group_quota) if group_quota <= 0 and group_quota != -2: error_msg = 'No group quota.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) if is_org_context(request): # request called by org admin org_id = request.user.org.org_id else: org_id = -1 # create group owned repo group_id = int(group_id) if is_pro_version() and ENABLE_STORAGE_CLASSES: if STORAGE_CLASS_MAPPING_POLICY in ('USER_SELECT', 'ROLE_BASED'): storages = get_library_storages(request) storage_id = request.data.get("storage_id", None) if storage_id and storage_id not in [ s['storage_id'] for s in storages ]: error_msg = 'storage_id invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) repo_id = seafile_api.add_group_owned_repo( group_id, repo_name, permission, password, enc_version=ENCRYPTED_LIBRARY_VERSION, storage_id=storage_id) else: # STORAGE_CLASS_MAPPING_POLICY == 'REPO_ID_MAPPING' if org_id and org_id > 0: repo_id = seafile_api.org_add_group_owned_repo( org_id, group_id, repo_name, permission, password, ENCRYPTED_LIBRARY_VERSION) else: repo_id = seafile_api.add_group_owned_repo( group_id, repo_name, permission, password, ENCRYPTED_LIBRARY_VERSION) else: if org_id and org_id > 0: repo_id = seafile_api.org_add_group_owned_repo( org_id, group_id, repo_name, permission, password, ENCRYPTED_LIBRARY_VERSION) else: repo_id = seafile_api.add_group_owned_repo( group_id, repo_name, permission, password, ENCRYPTED_LIBRARY_VERSION) # for activities username = request.user.username library_template = request.data.get("library_template", '') repo_created.send(sender=None, org_id=org_id, creator=username, repo_id=repo_id, repo_name=repo_name, library_template=library_template) # for notification repo = seafile_api.get_repo(repo_id) share_repo_to_group_successful.send(sender=None, from_user=username, group_id=group_id, repo=repo, path='/', org_id=org_id) info = get_group_owned_repo_info(request, repo_id) # TODO info['permission'] = permission return Response(info)
def do_action(self): now = datetime.datetime.now() try: cmd_last_check = CommandsLastCheck.objects.get( command_type=self.label) logger.debug('Last check time is %s' % cmd_last_check.last_check) unseen_notices = UserNotification.objects.get_all_notifications( seen=False, time_since=cmd_last_check.last_check) logger.debug('Update last check time to %s' % now) cmd_last_check.last_check = now cmd_last_check.save() except CommandsLastCheck.DoesNotExist: logger.debug('No last check time found, get all unread notices.') unseen_notices = UserNotification.objects.get_all_notifications( seen=False) logger.debug('Create new last check time: %s' % now) CommandsLastCheck(command_type=self.label, last_check=now).save() email_ctx = {} for notice in unseen_notices: if notice.to_user in email_ctx: email_ctx[notice.to_user] += 1 else: email_ctx[notice.to_user] = 1 for to_user, count in email_ctx.items(): # save current language cur_language = translation.get_language() # get and active user language user_language = self.get_user_language(to_user) translation.activate(user_language) logger.debug('Set language code to %s for user: %s' % (user_language, to_user)) self.stdout.write('[%s] Set language code to %s' % (str(datetime.datetime.now()), user_language)) notices = [] for notice in unseen_notices: logger.info('Processing unseen notice: [%s]' % (notice)) d = json.loads(notice.detail) repo_id = d.get('repo_id', None) group_id = d.get('group_id', None) try: if repo_id and not seafile_api.get_repo(repo_id): notice.delete() continue if group_id and not ccnet_api.get_group(group_id): notice.delete() continue except Exception as e: logger.error(e) continue if notice.to_user != to_user: continue elif notice.is_group_msg(): notice = self.format_group_message(notice) elif notice.is_repo_share_msg(): notice = self.format_repo_share_msg(notice) elif notice.is_repo_share_to_group_msg(): notice = self.format_repo_share_to_group_msg(notice) elif notice.is_file_uploaded_msg(): notice = self.format_file_uploaded_msg(notice) elif notice.is_group_join_request(): notice = self.format_group_join_request(notice) elif notice.is_add_user_to_group(): notice = self.format_add_user_to_group(notice) elif notice.is_file_comment_msg(): notice = self.format_file_comment_msg(notice) elif notice.is_guest_invitation_accepted_msg(): notice = self.format_guest_invitation_accepted_msg(notice) if notice is None: continue notices.append(notice) if not notices: continue contact_email = Profile.objects.get_contact_email_by_user(to_user) to_user = contact_email # use contact email if any c = { 'to_user': to_user, 'notice_count': count, 'notices': notices, } try: send_html_email( _('New notice on %s') % settings.SITE_NAME, 'notifications/notice_email.html', c, None, [to_user]) logger.info('Successfully sent email to %s' % to_user) self.stdout.write('[%s] Successfully sent email to %s' % (str(datetime.datetime.now()), to_user)) except Exception as e: logger.error('Failed to send email to %s, error detail: %s' % (to_user, e)) self.stderr.write( '[%s] Failed to send email to %s, error detail: %s' % (str(datetime.datetime.now()), to_user, e)) # restore current language translation.activate(cur_language)
def get(self, request): """ Get all share links of a user. Permission checking: 1. default(NOT guest) user; """ # get all share links username = request.user.username fileshares = FileShare.objects.filter(username=username) repo_id = request.GET.get('repo_id', None) if repo_id: 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) # filter share links by repo fileshares = filter(lambda fs: fs.repo_id == repo_id, fileshares) path = request.GET.get('path', None) if path: 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) # if path invalid, filter share links by repo if s_type == 'd' and path[-1] != '/': path = path + '/' fileshares = filter(lambda fs: fs.path == path, fileshares) links_info = [] for fs in fileshares: link_info = get_share_link_info(fs) links_info.append(link_info) if len(links_info) == 1: result = links_info else: dir_list = filter(lambda x: x['is_dir'], links_info) file_list = filter(lambda x: not x['is_dir'], links_info) dir_list.sort(lambda x, y: cmp(x['obj_name'], y['obj_name'])) file_list.sort(lambda x, y: cmp(x['obj_name'], y['obj_name'])) result = dir_list + file_list return Response(result)
def delete(self, request, workspace_id): """delete a table """ # argument check table_name = request.data.get('name') if not table_name: error_msg = 'name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) table_file_name = table_name + FILE_TYPE # resource check workspace = Workspaces.objects.get_workspace_by_id(workspace_id) if not workspace: error_msg = 'Workspace %s not found.' % workspace_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) repo_id = workspace.repo_id 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) dtable = DTables.objects.get_dtable(workspace, table_name) if not dtable: error_msg = 'dtable %s not found.' % table_name return api_error(status.HTTP_404_NOT_FOUND, error_msg) table_path = normalize_file_path(table_file_name) table_file_id = seafile_api.get_file_id_by_path(repo_id, table_path) if not table_file_id: error_msg = 'file %s not found.' % table_file_name return api_error(status.HTTP_404_NOT_FOUND, error_msg) # permission check username = request.user.username owner = workspace.owner if '@seafile_group' in owner: group_id = int(owner.split('@')[0]) if not is_group_member(group_id, username): error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) else: if username != owner: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # repo status check repo_status = repo.status if repo_status != 0: error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) # delete asset asset_dir_path = '/asset/' + str(dtable.uuid) asset_dir_id = seafile_api.get_dir_id_by_path(repo_id, asset_dir_path) if asset_dir_id: parent_dir = os.path.dirname(asset_dir_path) file_name = os.path.basename(asset_dir_path) try: seafile_api.del_file(repo_id, parent_dir, file_name, owner) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) # delete table try: seafile_api.del_file(repo_id, '/', table_file_name, owner) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) try: DTables.objects.delete_dtable(workspace, table_name) except Exception as e: logger.error(e) error_msg = 'Internal Server Error.' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return Response({'success': True}, status=status.HTTP_200_OK)
def delete(self, request, repo_id, format=None): if not seafile_api.get_repo(repo_id): return api_error(status.HTTP_400_BAD_REQUEST, 'Library does not exist') username = request.user.username share_type = request.GET.get('share_type', None) if share_type == 'personal': from_email = request.GET.get('from', None) if not is_valid_username(from_email): return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid argument') if is_org_context(request): org_id = request.user.org.org_id seaserv.seafserv_threaded_rpc.org_remove_share(org_id, repo_id, from_email, username) else: seaserv.remove_share(repo_id, from_email, username) elif share_type == 'group': from_email = request.GET.get('from', None) if not is_valid_username(from_email): return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid argument') group_id = request.GET.get('group_id', None) group = seaserv.get_group(group_id) if not group: return api_error(status.HTTP_400_BAD_REQUEST, 'Group does not exist') if not seaserv.check_group_staff(group_id, username) and \ not seafile_api.is_repo_owner(username, repo_id): return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied') if seaserv.is_org_group(group_id): org_id = seaserv.get_org_id_by_group(group_id) seaserv.del_org_group_repo(repo_id, org_id, group_id) else: seafile_api.unset_group_repo(repo_id, group_id, from_email) elif share_type == 'public': if is_org_context(request): org_repo_owner = seafile_api.get_org_repo_owner(repo_id) is_org_repo_owner = True if org_repo_owner == username else False if not request.user.org.is_staff and not is_org_repo_owner: return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied') org_id = request.user.org.org_id seaserv.seafserv_threaded_rpc.unset_org_inner_pub_repo(org_id, repo_id) else: if not seafile_api.is_repo_owner(username, repo_id) and \ not request.user.is_staff: return api_error(status.HTTP_403_FORBIDDEN, 'Permission denied') seaserv.unset_inner_pub_repo(repo_id) else: return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid argument') return Response({'success': True}, status=status.HTTP_200_OK)